├── .github
├── .gitkeep
└── workflows
│ └── rust_tests.yml
├── .gitignore
├── README.md
├── boilerplates
├── README.md
├── base64_encodings
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── benchmarking
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── command_line
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ │ └── main.rs
├── config_files
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── cpu_cores
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── csv_processing
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── debug_trait
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── directory_traversal
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── env_variables
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── exec_example
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── file_manipulation
│ ├── Cargo.toml
│ ├── result.txt
│ └── src
│ │ ├── README.md
│ │ └── main.rs
├── fractal
│ ├── Cargo.toml
│ ├── output.png
│ └── src
│ │ └── main.rs
├── handling_tarballs
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── hashmap
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── hex_encodings
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── hmac_hash
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── http_request
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── http_request_async
│ ├── Cargo.toml
│ ├── src
│ │ └── main.rs
│ └── tokio
│ │ ├── Cargo.toml
│ │ └── src
│ │ └── main.rs
├── json_processing
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── logging
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── pbkdf2
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── progress_bar
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── references
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── regex_replacing
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── sha256_hash
│ ├── Cargo.toml
│ ├── main.rs
│ └── src
│ │ └── main.rs
├── signal_handling
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── tcp_ports
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
└── testing
│ ├── Cargo.toml
│ └── src
│ ├── main.rs
│ └── test_fail.rs
├── notes
├── rust_async.md
├── rust_errors.md
├── rust_memory.md
├── rust_tests.md
├── rust_tldr.md
└── rust_tricks.md
└── w3kit
├── .env.example
├── Cargo.toml
├── Makefile
├── README.md
└── src
├── arbitrum
├── connector.rs
└── mod.rs
├── avalanche
├── connector.rs
└── mod.rs
├── dexs
├── mod.rs
└── uniswapv2.rs
├── ethereum
├── connector.rs
└── mod.rs
├── main.rs
├── market
├── coingecko.rs
└── mod.rs
├── near
├── connector.rs
└── mod.rs
├── optimism
├── connector.rs
└── mod.rs
├── polygon
├── connector.rs
└── mod.rs
├── solana
├── connector.rs
└── mod.rs
└── utils
├── cli_handler.rs
├── commands.rs
├── maths.rs
└── mod.rs
/.github/.gitkeep:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/workflows/rust_tests.yml:
--------------------------------------------------------------------------------
1 | name: 👾 rust tests
2 |
3 | on:
4 | push:
5 | paths:
6 | - 'web3toolkit/'
7 |
8 | env:
9 | CARGO_TERM_COLOR: always
10 | RUST_BACKTRACE: 1
11 |
12 | jobs:
13 | cargo-check:
14 | runs-on: ${{ matrix.triple.os }}
15 | strategy:
16 | matrix:
17 | triple:
18 | - {
19 | os: "ubuntu-latest",
20 | target: "x86_64-unknown-linux-gnu",
21 | cross: false,
22 | }
23 | - {
24 | os: "macOS-latest",
25 | target: "x86_64-apple-darwin",
26 | cross: false,
27 | }
28 | # macOS ARM
29 | - {
30 | os: "macOS-latest",
31 | target: "aarch64-apple-darwin",
32 | cross: true,
33 | }
34 | steps:
35 | - name: Checkout
36 | uses: actions/checkout@v3
37 |
38 | - name: Install toolchain
39 | uses: actions-rs/toolchain@v1
40 | with:
41 | profile: minimal
42 | toolchain: stable
43 | override: true
44 | target: ${{ matrix.triple.target }}
45 |
46 | - name: Cache cargo
47 | uses: actions/cache@v3
48 | with:
49 | path: |
50 | ~/.cargo/bin/
51 | ~/.cargo/registry/index/
52 | ~/.cargo/registry/cache/
53 | ~/.cargo/git/db/
54 | target/
55 | key: ${{ runner.os }}-${{ matrix.triple.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
56 |
57 | - name: Cargo check
58 | uses: actions-rs/cargo@v1
59 | with:
60 | command: check
61 | args: --all-targets --verbose --target=${{ matrix.triple.target }}
62 | use-cross: ${{ matrix.triple.cross }}
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | Cargo.lock
3 | **/*.rs.bk
4 | .env
5 | target
6 | src/target
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## ⛓️🧰🦀 web3 toolkit - rust edition
2 |
3 |
4 |
5 |
6 | * **[a tl;dr to get started with rust](notes/rust_tldr.md)**
7 | * then check these *ongoing* notes:
8 | * **[rust tricks](notes/rust_tricks.md)**
9 | * **[async for rust](notes/rust_async.md)**
10 | * **[memory management in rust](notes/rust_memory.md)**
11 | * **[error handling in rust](notes/rust_errors.md)**
12 | * **[writing tests in rust](notes/rust_tests.md)**
13 |
14 | * **[w3kit](w3kit)**: (*ongoing*) development of a crate for on-chain ops on **several blockchains** (published at **[crates.io](https://crates.io/crates/w3kit)** so it can be imported as a library with `cargo add w3kit`)
15 | * **[boilerplate snippets](boilerplates)**: cryptographic primitives, handling files, benchmarking, etc.
16 |
17 |
18 |
19 |
20 |
21 | ----
22 |
23 | #### external resources
24 |
25 | * **[installing guide](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/)**
26 | * **[cargo dep manager and build tool](https://doc.rust-lang.org/cargo/)**
27 | * **[rustfmt code style](https://github.com/rust-lang/rustfmt)**
28 | * **[rust standard library](https://doc.rust-lang.org/std/index.html)**
29 | * **[rust docs](https://doc.rust-lang.org/stable/book/)**
30 | * **[gentle intro to rust](https://stevedonovan.github.io/rust-gentle-intro/readme.html)**
31 | * **[ethereum foundation on rust](https://ethereum.org/en/developers/docs/programming-languages/rust/)**
32 | * **[google rust course](https://github.com/google/comprehensive-rust)**
33 |
34 | ##### developing
35 |
36 | * **[beginner's guide to error handling in rust](https://www.sheshbabu.com/posts/rust-error-handling/)**
37 | * **[publishing a crate in crate.ios](https://doc.rust-lang.org/cargo/reference/publishing.html)**
38 | * **[cargo book on tests](https://doc.rust-lang.org/cargo/guide/tests.html)**
39 | * **[introducing foundry, by paradigm](https://www.paradigm.xyz/2021/12/introducing-the-foundry-ethereum-development-toolbox)**
40 | * **[invariant testing weth with foundry](https://mirror.xyz/horsefacts.eth/Jex2YVaO65dda6zEyfM_-DXlXhOWCAoSpOx5PLocYgw)**
41 | * **[comparison of rust async and linux thread switch time](https://github.com/jimblandy/context-switch)**
42 | * **[dotenv array for dotenv vars](https://crates.io/crates/dotenv)**
43 | * **[clap array for menu and argparse](https://docs.rs/clap/latest/clap/)**
44 | * **[reqwest higher-level HTTP Client.](https://docs.rs/reqwest/latest/reqwest/)**
45 | * **[tokio crate for async, multi-threading](https://tokio.rs/tokio/tutorial/async)**
46 | * **[serde crate for serializing](https://serde.rs/)**
47 | * **[chrono crate for date and time](https://docs.rs/chrono/latest/chrono/)**
48 | * **[comfy-table pprint beautiful data tables](https://crates.io/crates/comfy-table)**
49 | * **[once_cell crate for single assignments cells](https://crates.io/crates/once_cell)**
50 | * **[ndarray crate for matrices](https://docs.rs/ndarray/0.15.6/ndarray/index.html)**
51 | * **[hashmap crate using a hashing algorithm resistant against hashdos attacks](https://doc.rust-lang.org/std/collections/struct.HashMap.html)**
52 | * **[anyhow crate provides a trait to customize error handling](https://docs.rs/anyhow/latest/anyhow/)**
53 |
54 | ##### web3-related
55 |
56 | * **[blockchain-science-rs](https://github.com/autistic-symposium/blockchain-science-rs):** *ongoing* on-chain research, foundry science, defi analysis, and bots
57 | * **[near api](https://crates.io/crates/near-api-tokio)**
58 | * **[ethers-provider](https://crates.io/crates/ethers-providers)**
59 | * **[web3 ethereum JSON-RPC client](https://crates.io/crates/web3)**
60 | * **[ether.js vs. ether-rs mempool stream benchmark](https://github.com/CodeForcer/rust-pending-stream)**
61 | * **[ring crate for boringSSL cryptographic primitives](https://briansmith.org/rustdoc/ring/index.html)**
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/boilerplates/README.md:
--------------------------------------------------------------------------------
1 | ## 🦀 boilerplates for rust projects
2 |
3 |
4 |
5 | #### disclaimer: many of these boilerplates are not my code but i am dumping them here because i use them and they are well-known and relevant references.
6 |
7 |
8 |
9 | * **[parse cli](command_line/)**
10 | * **[handling tarballs](handling_tarballs/)**
11 | * **[benchmarking](benchmarking/)**
12 | * **[command line](command_line/)**
13 | * **[a julia fractal](fractal/)**
14 | * **[hmac hash](hmac_hash/)**
15 | * **[pbkdf2 primitive](pbkdf2/)**
16 | * **[sha256 primitive](sha256_hash/)**
17 | * **[hex enc-decoding](hex_encodings/)**
18 | * **[base64 enc-decoding](base64_encodings/)**
19 | * **[csv processing](csv_processing/)**
20 | * **[json processing](json_processing/)**
21 | * **[file handling](file_manipulation/)**
22 | * **[directory traversal](directory_traversal/)**
23 | * **[number of cpu cores](cpu_cores/)**
24 | * **[hashmap and lazy_static](hashmap/)**
25 | * **[tcp/ip ports](tcp_ports/)**
26 | * **[exec example](exec_example/)**
27 | * **[read env variables](env_variables/)**
28 | * **[regex replacing](regex_replacing/)**
29 | * **[http get request](http_request/)**
30 | * **[http get request async](http_request_async/)**
31 | * **[values by reference](references./)**
32 | * **[signal handling](signal_handling/)**
33 | * **[progress bar](progress_bar/)**
34 | * **[custom debug trait](debug_trait/)**
35 | * **[logging](logging)**
36 | * **[testing](testing)**
37 |
38 |
39 |
40 | run any of these snippets with:
41 |
42 | ```shell
43 | cargo run
44 | ```
45 |
--------------------------------------------------------------------------------
/boilerplates/base64_encodings/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "base64_encodings"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | base64 = "0.21.2"
10 | encode = "0.1.0"
11 | error-chain = "0.12.4"
12 |
--------------------------------------------------------------------------------
/boilerplates/base64_encodings/src/main.rs:
--------------------------------------------------------------------------------
1 | use error_chain::error_chain;
2 |
3 | use std::str;
4 | use base64::{encode, decode};
5 |
6 | error_chain! {
7 | foreign_links {
8 | Base64(base64::DecodeError);
9 | Utf8Error(str::Utf8Error);
10 | }
11 | }
12 |
13 | fn main() -> Result<()> {
14 | let hello = b"hello cypherpunks";
15 | let encoded = encode(hello);
16 | let decoded = decode(&encoded)?;
17 |
18 | println!("origin: {}", str::from_utf8(hello)?);
19 | println!("base64 encoded: {}", encoded);
20 | println!("back to origin: {}", str::from_utf8(&decoded)?);
21 |
22 | Ok(())
23 | }
24 |
--------------------------------------------------------------------------------
/boilerplates/benchmarking/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "benchmarking"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | chrono = "0.4.26"
10 | local = "0.1.0"
11 | utc = "0.2.0"
12 |
--------------------------------------------------------------------------------
/boilerplates/benchmarking/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::thread;
2 | use std::time::{Duration, Instant};
3 | use chrono::{DateTime, FixedOffset, Local, Utc, Datelike, Timelike, NaiveDate, NaiveDateTime};
4 |
5 | fn expensive_function() {
6 | thread::sleep(Duration::from_secs(1));
7 | }
8 |
9 | fn main() {
10 |
11 | // example of how to benchmark a function
12 | let start = Instant::now();
13 | expensive_function();
14 | let duration = start.elapsed();
15 |
16 | println!("Time elapsed in expensive_function() is: {:?}\n", duration);
17 |
18 | // converting local time to ano
19 | let local_time = Local::now();
20 | let utc_time = DateTime::::from_utc(local_time.naive_utc(), Utc);
21 | let china_timezone = FixedOffset::east(8 * 3600);
22 | let rio_timezone = FixedOffset::west(2 * 3600);
23 | println!("Local time now is {}", local_time);
24 | println!("UTC time now is {}", utc_time);
25 | println!(
26 | "Time in Hong Kong now is {}",
27 | utc_time.with_timezone(&china_timezone)
28 | );
29 | println!("Time in Rio de Janeiro now is {}\n", utc_time.with_timezone(&rio_timezone));
30 |
31 | // examine date and time
32 | let now = Utc::now();
33 |
34 | let (is_pm, hour) = now.hour12();
35 | println!(
36 | "The current UTC time is {:02}:{:02}:{:02} {}",
37 | hour,
38 | now.minute(),
39 | now.second(),
40 | if is_pm { "PM" } else { "AM" }
41 | );
42 | println!(
43 | "And there have been {} seconds since midnight\n",
44 | now.num_seconds_from_midnight()
45 | );
46 |
47 | let (is_common_era, year) = now.year_ce();
48 | println!(
49 | "The current UTC date is {}-{:02}-{:02} {:?} ({})",
50 | year,
51 | now.month(),
52 | now.day(),
53 | now.weekday(),
54 | if is_common_era { "CE" } else { "BCE" }
55 | );
56 | println!(
57 | "And the Common Era began {} days ago\n",
58 | now.num_days_from_ce()
59 | );
60 |
61 | // convert data to unix timestamp
62 | let date_time: NaiveDateTime = NaiveDate::from_ymd(2017, 11, 12).and_hms(17, 33, 44);
63 | println!(
64 | "Number of seconds between 1970-01-01 00:00:00 and {} is {}.",
65 | date_time, date_time.timestamp());
66 |
67 | let date_time_after_a_billion_seconds = NaiveDateTime::from_timestamp(1_000_000_000, 0);
68 | println!(
69 | "Date after a billion seconds since 1970-01-01 00:00:00 was {}.\n",
70 | date_time_after_a_billion_seconds);
71 |
72 | // display date and time
73 | let now: DateTime = Utc::now();
74 |
75 | println!("UTC now is: {}", now);
76 | println!("UTC now in RFC 2822 is: {}", now.to_rfc2822());
77 | println!("UTC now in RFC 3339 is: {}", now.to_rfc3339());
78 | println!("UTC now in a custom format is: {}\n", now.format("%a %b %e %T %Y"));
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/boilerplates/command_line/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "command_line"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | arg = "0.4.1"
10 | clap = { version = "4.3.11", features = ["derive"] }
11 |
--------------------------------------------------------------------------------
/boilerplates/command_line/README.md:
--------------------------------------------------------------------------------
1 | ## command line arguments
2 |
3 |
4 |
5 |
6 | ### `std::env::args`
7 |
8 |
9 |
10 | * `std::env::args` is how you access command-line arguments. it returns an iterator over the arguments as strings:
11 |
12 | ```rust
13 | fn main() {
14 | for arg in std::env::args() {
15 | println!("'{}'", arg);
16 | }
17 | }
18 | ```
19 |
20 | * you can also use `Vec` and `collect` to make that a vector, and using the iterator `skip` method to move:
21 |
22 | ```rust
23 | let args: Vec = std::env::args().skip(1).collect();
24 | if args.len() > 0 {
25 | ...
26 | }
27 | ```
28 |
29 | * or using a single argument together with parsing an integer value:
30 |
31 | ```rust
32 | use std::env;
33 |
34 | fn main() {
35 | let first = env::args().nth(1).expect("please supply an argument");
36 | let n: i32 = first.parse().expect("not an integer!");
37 | // do stuff
38 | }
39 | ```
40 |
41 |
42 |
43 | ### `clap`
44 |
45 | * the [clap](https://docs.rs/clap/latest/clap/) crate makes thing easier.
46 |
--------------------------------------------------------------------------------
/boilerplates/command_line/src/main.rs:
--------------------------------------------------------------------------------
1 | // run with target/debug/command_line --name
2 |
3 | use clap::Parser;
4 |
5 | #[derive(Parser, Debug)]
6 | #[command(author, version, about, long_about = None)]
7 |
8 | struct Args {
9 |
10 | #[arg(short, long)]
11 | name: String,
12 |
13 | #[arg(short, long, default_value_t = 1)]
14 | count: u8,
15 | }
16 |
17 | fn main() {
18 | let args = Args::parse();
19 |
20 | for _ in 0..args.count {
21 | println!("Hello {}!", args.name)
22 | }
23 | }
--------------------------------------------------------------------------------
/boilerplates/config_files/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "config_files"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | confy = "0.5.1"
10 |
--------------------------------------------------------------------------------
/boilerplates/config_files/src/main.rs:
--------------------------------------------------------------------------------
1 | #[derive(Debug, Serialize, Deserialize)]
2 | struct MyConfig {
3 | name: String,
4 | comfy: bool,
5 | foo: i64,
6 | }
7 |
8 | fn main() -> Result<(), io::Error> {
9 | let cfg: MyConfig = confy::load("my_app")?;
10 | println!("{:#?}", cfg);
11 | Ok(())
12 | }
13 |
--------------------------------------------------------------------------------
/boilerplates/cpu_cores/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "cpu_cores"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | num_cpus = "1.16.0"
10 |
--------------------------------------------------------------------------------
/boilerplates/cpu_cores/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 |
3 | println!("Number of logical cores is {}", num_cpus::get());
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/boilerplates/csv_processing/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "csv_processing"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | csv = "1.2.2"
10 | io = "0.0.2"
11 | serde = { version = "1.0", features = ["derive"] }
12 |
--------------------------------------------------------------------------------
/boilerplates/csv_processing/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::io;
2 | use csv::Error;
3 | use serde::Deserialize;
4 |
5 |
6 | #[derive(Deserialize)]
7 | struct Record {
8 | year: u16,
9 | make: String,
10 | model: String,
11 | description: String,
12 | }
13 |
14 |
15 | fn main() -> Result<(), Error> {
16 |
17 | // example of using csv crate for parsing csv files
18 | let csv = "year,make,model,description
19 | 1948,Porsche,356,Luxury sports car
20 | 1967,Ford,Mustang fastback 1967,American car";
21 |
22 | let mut reader = csv::Reader::from_reader(csv.as_bytes());
23 | for record in reader.records() {
24 | let record = record?;
25 | println!(
26 | "In {}, {} built the {} model. It is a {}.",
27 | &record[0],
28 | &record[1],
29 | &record[2],
30 | &record[3]
31 | );
32 | }
33 |
34 | // example of using serde crate for parsing csv files
35 | for record in reader.deserialize() {
36 | let record: Record = record?;
37 | println!(
38 | "In {}, {} built the {} model. It is a {}.",
39 | record.year,
40 | record.make,
41 | record.model,
42 | record.description
43 | );
44 | }
45 |
46 | // serialize records to csv
47 | let mut wtr = csv::Writer::from_writer(io::stdout());
48 |
49 | wtr.write_record(&["Name", "Place", "ID"])?;
50 |
51 | wtr.serialize(("Mark", "Sydney", 87))?;
52 | wtr.serialize(("Ashley", "Dublin", 32))?;
53 | wtr.serialize(("Akshat", "Delhi", 11))?;
54 |
55 | wtr.flush()?;
56 |
57 | Ok(())
58 | }
59 |
--------------------------------------------------------------------------------
/boilerplates/debug_trait/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "debug_trait"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/debug_trait/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::fmt;
2 |
3 | struct Person {
4 | first_name: String,
5 | last_name: String,
6 | }
7 |
8 | impl fmt::Debug for Person {
9 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10 | write!(f, "{} {}", self.first_name, self.last_name)
11 | }
12 | }
13 |
14 |
15 | fn main() {
16 | let p = Person {
17 | first_name: "John".to_string(),
18 | last_name: "Snow".to_string(),
19 | };
20 | println!("{:?}", p);
21 | }
22 |
--------------------------------------------------------------------------------
/boilerplates/directory_traversal/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "directory_traversal"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | error-chain = "0.12.4"
10 |
--------------------------------------------------------------------------------
/boilerplates/directory_traversal/src/main.rs:
--------------------------------------------------------------------------------
1 | use error_chain::error_chain;
2 |
3 | use std::{env, fs};
4 |
5 | error_chain! {
6 | foreign_links {
7 | Io(std::io::Error);
8 | SystemTimeError(std::time::SystemTimeError);
9 | }
10 | }
11 |
12 | fn main() -> Result<()> {
13 | let current_dir = env::current_dir()?;
14 | println!(
15 | "Entries modified in the last 24 hours in {:?}:",
16 | current_dir
17 | );
18 |
19 | for entry in fs::read_dir(current_dir)? {
20 | let entry = entry?;
21 | let path = entry.path();
22 |
23 | let metadata = fs::metadata(&path)?;
24 | let last_modified = metadata.modified()?.elapsed()?.as_secs();
25 |
26 | if last_modified < 24 * 3600 && metadata.is_file() {
27 | println!(
28 | "\nLast modified: {:?} seconds, is read only: {:?}, size: {:?} bytes, filename: {:?}\n",
29 | last_modified,
30 | metadata.permissions().readonly(),
31 | metadata.len(),
32 | path.file_name().ok_or("No filename")?
33 | );
34 | }
35 | }
36 |
37 | Ok(())
38 | }
39 |
--------------------------------------------------------------------------------
/boilerplates/env_variables/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "env_variables"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/env_variables/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::env;
2 | use std::fs;
3 | use std::io::Error;
4 |
5 | fn main() -> Result<(), Error> {
6 |
7 | const DEFAULT_CONFIG: &str = ".env";
8 | let config_path = env::var("CONFIG")
9 | .unwrap_or(DEFAULT_CONFIG.to_string());
10 |
11 | let config: String = fs::read_to_string(config_path)?;
12 | println!("Config: {}", config);
13 |
14 | Ok(())
15 | }
16 |
--------------------------------------------------------------------------------
/boilerplates/exec_example/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exec_example"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | error-chain = "0.12.4"
10 |
--------------------------------------------------------------------------------
/boilerplates/exec_example/src/main.rs:
--------------------------------------------------------------------------------
1 | use error_chain::error_chain;
2 | use std::io::Write;
3 | use std::collections::HashSet;
4 | use std::process::{Command, Stdio};
5 |
6 | error_chain!{
7 | errors { CmdError }
8 | foreign_links {
9 | Io(std::io::Error);
10 | Utf8(std::string::FromUtf8Error);
11 | }
12 | }
13 |
14 | fn main() -> Result<()> {
15 |
16 | // exec run some command and print the output
17 | const CMD: &str = "ls";
18 | let mut child = Command::new(CMD).stdin(Stdio::piped())
19 | .stderr(Stdio::piped())
20 | .stdout(Stdio::piped())
21 | .spawn()?;
22 |
23 | child.stdin
24 | .as_mut()
25 | .ok_or("\nChild process stdin has not been captured!")?
26 | .write_all(b"import this; copyright(); credits(); exit()")?;
27 |
28 | let output = child.wait_with_output()?;
29 |
30 | if output.status.success() {
31 | let raw_output = String::from_utf8(output.stdout)?;
32 | let words = raw_output.split_whitespace()
33 | .map(|s| s.to_lowercase())
34 | .collect::>();
35 | println!("Command produces {} words:", words.len());
36 | println!("{:#?}", words);
37 | } else {
38 | let err = String::from_utf8(output.stderr)?;
39 | error_chain::bail!("External command failed:\n {}", err)
40 | }
41 |
42 | // run a piped command
43 | let directory = std::env::current_dir()?;
44 | let mut du_output_child = Command::new("du")
45 | .arg("-ah")
46 | .arg(&directory)
47 | .stdout(Stdio::piped())
48 | .spawn()?;
49 |
50 | if let Some(du_output) = du_output_child.stdout.take() {
51 | let mut sort_output_child = Command::new("sort")
52 | .arg("-hr")
53 | .stdin(du_output)
54 | .stdout(Stdio::piped())
55 | .spawn()?;
56 |
57 | du_output_child.wait()?;
58 |
59 | if let Some(sort_output) = sort_output_child.stdout.take() {
60 | let head_output_child = Command::new("head")
61 | .args(&["-n", "10"])
62 | .stdin(sort_output)
63 | .stdout(Stdio::piped())
64 | .spawn()?;
65 |
66 | let head_stdout = head_output_child.wait_with_output()?;
67 |
68 | sort_output_child.wait()?;
69 |
70 | println!(
71 | "\nTop 10 biggest files and directories in '{}':\n{}",
72 | directory.display(),
73 | String::from_utf8(head_stdout.stdout).unwrap()
74 | );
75 | }
76 | }
77 | Ok(())
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/boilerplates/file_manipulation/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "file_manipulation"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/file_manipulation/result.txt:
--------------------------------------------------------------------------------
1 | Cyph3r
2 | 👾
--------------------------------------------------------------------------------
/boilerplates/file_manipulation/src/README.md:
--------------------------------------------------------------------------------
1 | ## file handling
2 |
3 |
4 |
5 |
6 | #### option 1
7 |
8 |
9 |
10 | ```rust
11 | use std::fs::File;
12 | use std::io::{Write, BufReader, BufRead, Error};
13 |
14 |
15 | fn main() -> Result<(), Error> {
16 | const FILEPATH: &str = "result.txt";
17 |
18 | // write to file
19 | let mut output = File::create(&FILEPATH)?;
20 | write!(output, "Cyph3r\n👾")?;
21 |
22 | // read from file
23 | let input = File::open(&FILEPATH)?;
24 | let buffered = BufReader::new(input);
25 |
26 | for line in buffered.lines() {
27 | println!("{}", line?);
28 | }
29 |
30 | Ok(())
31 | }
32 | ```
33 |
34 |
35 |
36 |
37 | #### option 2
38 |
39 |
40 |
41 | ```rust
42 | use std::env;
43 | use std::io;
44 | use std::fs::File;
45 | use std::io::Read;
46 |
47 | fn read_to_string(filename: &str) -> io::Result {
48 | let mut file = File::open(&filename)?;
49 | let mut text = String::new();
50 | file.read_to_string(&mut text)?;
51 | Ok(text)
52 | }
53 |
54 | fn main() {
55 | let file = env::args().nth(1).expect("please give a filename");
56 | let text = read_to_string(&file).expect("bad name");
57 |
58 | println!("file had {} bytes", text.len());
59 | }
60 | ```
--------------------------------------------------------------------------------
/boilerplates/file_manipulation/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::io;
2 | use std::env;
3 | use std::io::Read;
4 | use std::fs::File;
5 | use std::io::{Write, BufReader, BufRead, Error};
6 |
7 |
8 | fn read_to_string(filename: &str) -> io::Result {
9 | let mut file = File::open(&filename)?;
10 | let mut text = String::new();
11 | file.read_to_string(&mut text)?;
12 | Ok(text)
13 | }
14 |
15 | fn main() -> Result<(), Error> {
16 | const FILEPATH: &str = "result.txt";
17 |
18 | // write to file
19 | let mut output = File::create(&FILEPATH)?;
20 | write!(output, "Cyph3r\n👾")?;
21 |
22 | // read from file
23 | let input = File::open(&FILEPATH)?;
24 | let buffered = BufReader::new(input);
25 |
26 | for line in buffered.lines() {
27 | println!("{}", line?);
28 | }
29 |
30 | // using read_to_string
31 | let file = env::args().nth(1).expect("please give a filename");
32 | let text = read_to_string(&file).expect("bad name");
33 |
34 | println!("file had {} bytes", text.len());
35 |
36 | Ok(())
37 | }
38 |
--------------------------------------------------------------------------------
/boilerplates/fractal/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "fractal"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | error-chain = "0.12.4"
10 | image = "0.24.6"
11 | num = "0.4.0"
12 | num_cpus = "1.16.0"
13 | threadpool = "1.8.1"
14 |
--------------------------------------------------------------------------------
/boilerplates/fractal/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autistic-symposium/web3-starter-rs/8ca957542d490e81dc39f2c1bf1ff6d3f12f1d4d/boilerplates/fractal/output.png
--------------------------------------------------------------------------------
/boilerplates/fractal/src/main.rs:
--------------------------------------------------------------------------------
1 | // https://rust-lang-nursery.github.io/rust-cookbook/concurrency/threads.html
2 |
3 | use error_chain::error_chain;
4 | use std::sync::mpsc::{channel, RecvError};
5 | use threadpool::ThreadPool;
6 | use num::complex::Complex;
7 | use image::{ImageBuffer, Pixel, Rgb};
8 |
9 | error_chain! {
10 | foreign_links {
11 | MpscRecv(RecvError);
12 | Io(std::io::Error);
13 | }
14 | }
15 |
16 | // Function converting intensity values to RGB
17 | // Based on http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm
18 | fn wavelength_to_rgb(wavelength: u32) -> Rgb {
19 | let wave = wavelength as f32;
20 |
21 | let (r, g, b) = match wavelength {
22 | 380..=439 => ((440. - wave) / (440. - 380.), 0.0, 1.0),
23 | 440..=489 => (0.0, (wave - 440.) / (490. - 440.), 1.0),
24 | 490..=509 => (0.0, 1.0, (510. - wave) / (510. - 490.)),
25 | 510..=579 => ((wave - 510.) / (580. - 510.), 1.0, 0.0),
26 | 580..=644 => (1.0, (645. - wave) / (645. - 580.), 0.0),
27 | 645..=780 => (1.0, 0.0, 0.0),
28 | _ => (0.0, 0.0, 0.0),
29 | };
30 |
31 | let factor = match wavelength {
32 | 380..=419 => 0.3 + 0.7 * (wave - 380.) / (420. - 380.),
33 | 701..=780 => 0.3 + 0.7 * (780. - wave) / (780. - 700.),
34 | _ => 1.0,
35 | };
36 |
37 | let (r, g, b) = (normalize(r, factor), normalize(g, factor), normalize(b, factor));
38 | Rgb::from_channels(r, g, b, 0)
39 | }
40 |
41 | // Maps Julia set distance estimation to intensity values
42 | fn julia(c: Complex, x: u32, y: u32, width: u32, height: u32, max_iter: u32) -> u32 {
43 | let width = width as f32;
44 | let height = height as f32;
45 |
46 | let mut z = Complex {
47 | // scale and translate the point to image coordinates
48 | re: 3.0 * (x as f32 - 0.5 * width) / width,
49 | im: 2.0 * (y as f32 - 0.5 * height) / height,
50 | };
51 |
52 | let mut i = 0;
53 | for t in 0..max_iter {
54 | if z.norm() >= 2.0 {
55 | break;
56 | }
57 | z = z * z + c;
58 | i = t;
59 | }
60 | i
61 | }
62 |
63 | // Normalizes color intensity values within RGB range
64 | fn normalize(color: f32, factor: f32) -> u8 {
65 | ((color * factor).powf(0.8) * 255.) as u8
66 | }
67 |
68 | fn main() {
69 | let (width, height) = (1920, 1080);
70 | let mut img = ImageBuffer::new(width, height);
71 | let iterations = 300;
72 |
73 | let c = Complex::new(-0.8, 0.156);
74 |
75 | let pool = ThreadPool::new(num_cpus::get());
76 | let (tx, rx) = channel();
77 |
78 | for y in 0..height {
79 | let tx = tx.clone();
80 | pool.execute(move || for x in 0..width {
81 | let i = julia(c, x, y, width, height, iterations);
82 | let pixel = wavelength_to_rgb(380 + i * 400 / iterations);
83 | tx.send((x, y, pixel)).expect("Could not send data!");
84 | });
85 | }
86 |
87 | for _ in 0..(width * height) {
88 | let Ok((x, y, pixel)) = rx.recv() else { todo!() };
89 | img.put_pixel(x, y, pixel);
90 | }
91 | let _ = img.save("output.png");
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/boilerplates/handling_tarballs/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "handling_tarballs"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | flate2 = "1.0.26"
10 | tar = "0.4.38"
11 |
--------------------------------------------------------------------------------
/boilerplates/handling_tarballs/src/main.rs:
--------------------------------------------------------------------------------
1 |
2 | use std::fs::File;
3 | use tar::Archive;
4 | use flate2::Compression;
5 | use flate2::read::GzDecoder;
6 | use flate2::write::GzEncoder;
7 |
8 |
9 | fn main() -> Result<(), std::io::Error> {
10 | let path = "archive.tar.gz";
11 |
12 | // Decompress the archive
13 | let tar_gz = File::open(path)?;
14 | let tar = GzDecoder::new(tar_gz);
15 | let mut archive = Archive::new(tar);
16 | archive.unpack(".")?;
17 |
18 | // Compress the archive
19 | let tar_gz = File::create("archive.tar.gz")?;
20 | let enc = GzEncoder::new(tar_gz, Compression::default());
21 | let mut tar = tar::Builder::new(enc);
22 | tar.append_dir_all("backup/logs", "/var/log")?;
23 |
24 |
25 | Ok(())
26 | }
27 |
--------------------------------------------------------------------------------
/boilerplates/hashmap/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "hashmap"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | lazy_static = "1.4.0"
10 |
--------------------------------------------------------------------------------
/boilerplates/hashmap/src/main.rs:
--------------------------------------------------------------------------------
1 | use lazy_static::lazy_static;
2 | use std::collections::HashMap;
3 |
4 |
5 | lazy_static! {
6 | static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = {
7 | let mut map = HashMap::new();
8 | map.insert("Lilith", vec!["user", "admin"]);
9 | map.insert("Osiris", vec!["user"]);
10 | map
11 | };
12 | }
13 |
14 | fn show_access(name: &str) {
15 | let access = PRIVILEGES.get(name);
16 | println!("{}: {:?}", name, access);
17 | }
18 |
19 |
20 | fn main() {
21 | let access = PRIVILEGES.get("Lilith");
22 | println!("Lilith: {:?}", access);
23 |
24 | show_access("Adam");
25 | }
26 |
--------------------------------------------------------------------------------
/boilerplates/hex_encodings/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "hex_encodings"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | data-encoding = "2.4.0"
10 |
--------------------------------------------------------------------------------
/boilerplates/hex_encodings/src/main.rs:
--------------------------------------------------------------------------------
1 | use data_encoding::{HEXUPPER, DecodeError};
2 |
3 | fn main() -> Result<(), DecodeError> {
4 | let original = b"Stoic cypherpunks in the future.";
5 | println!("Original in bytes: {:?}", &original);
6 |
7 | let encoded = HEXUPPER.encode(original);
8 | println!("Encoded: {encoded}");
9 |
10 | let decoded = HEXUPPER.decode(&encoded.into_bytes())?;
11 | println!("Decoded in bytes: {:?}", &decoded);
12 | println!("Decoded as string: {}", String::from_utf8_lossy(&decoded));
13 |
14 | Ok(())
15 | }
16 |
--------------------------------------------------------------------------------
/boilerplates/hmac_hash/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "hmac_hash"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | ring = "0.16.20"
10 |
--------------------------------------------------------------------------------
/boilerplates/hmac_hash/src/main.rs:
--------------------------------------------------------------------------------
1 | use ring::{hmac, rand};
2 | use ring::rand::SecureRandom;
3 | use ring::error::Unspecified;
4 |
5 | fn main() -> Result<(), Unspecified> {
6 | let mut key_value = [0u8; 48];
7 | let rng = rand::SystemRandom::new();
8 | rng.fill(&mut key_value)?;
9 | let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value);
10 |
11 | let message = "Legitimate and important message.";
12 | let signature = hmac::sign(&key, message.as_bytes());
13 | hmac::verify(&key, message.as_bytes(), signature.as_ref())?;
14 |
15 | Ok(())
16 | }
17 |
--------------------------------------------------------------------------------
/boilerplates/http_request/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "http_request"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | error-chain = "0.12.4"
10 | reqwest = { version = "0.11.18", features = ["blocking"] }
11 | tokio = "1.29.1"
12 |
13 |
--------------------------------------------------------------------------------
/boilerplates/http_request/src/main.rs:
--------------------------------------------------------------------------------
1 | use error_chain::error_chain;
2 | use std::io::Read;
3 |
4 | error_chain! {
5 | foreign_links {
6 | Io(std::io::Error);
7 | HttpRequest(reqwest::Error);
8 | }
9 | }
10 |
11 | fn main() -> Result<()> {
12 |
13 | // parse URL and makes a synchronous request
14 | const URL: &str = "http://google.com";
15 | let mut res = reqwest::blocking::get(URL)?;
16 | let mut body = String::new();
17 | res.read_to_string(&mut body)?;
18 |
19 | println!("Status: {}", res.status());
20 | println!("Headers:\n{:#?}", res.headers());
21 | println!("Body:\n{}", body);
22 |
23 | Ok(())
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/boilerplates/http_request_async/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "http_request_async"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | error-chain = "0.12.4"
10 | reqwest = "0.11.18"
11 | tokio = {version = "1.29.1", features = ["full"] }
12 |
--------------------------------------------------------------------------------
/boilerplates/http_request_async/src/main.rs:
--------------------------------------------------------------------------------
1 | // handles all the heavy executor setup and allows sequential
2 | // code implemented without blocking until .await
3 |
4 | use error_chain::error_chain;
5 |
6 | error_chain! {
7 | foreign_links {
8 | Io(std::io::Error);
9 | HttpRequest(reqwest::Error);
10 | }
11 | }
12 |
13 |
14 | #[tokio::main]
15 | async fn main() -> Result<()> {
16 |
17 | const URL: &str = "http://google.com";
18 | let res = reqwest::get(URL).await?;
19 | println!("Status: {}", res.status());
20 | println!("Headers:\n{:#?}", res.headers());
21 |
22 | let body = res.text().await?;
23 | println!("Body:\n{}", body);
24 | Ok(())
25 | }
26 |
--------------------------------------------------------------------------------
/boilerplates/http_request_async/tokio/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "tokio"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/http_request_async/tokio/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | println!("Hello, world!");
3 | }
4 |
--------------------------------------------------------------------------------
/boilerplates/json_processing/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "json_processing"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | serde_json = "1.0.100"
10 |
--------------------------------------------------------------------------------
/boilerplates/json_processing/src/main.rs:
--------------------------------------------------------------------------------
1 | use serde_json::json;
2 | use serde_json::{Value, Error};
3 |
4 | fn main() -> Result<(), Error> {
5 | let j = r#"{
6 | "userid": 103609,
7 | "verified": true,
8 | "access_privileges": [
9 | "user",
10 | "admin"
11 | ]
12 | }"#;
13 |
14 | let parsed: Value = serde_json::from_str(j)?;
15 |
16 | let expected = json!({
17 | "userid": 103609,
18 | "verified": true,
19 | "access_privileges": [
20 | "user",
21 | "admin"
22 | ]
23 | });
24 |
25 | assert_eq!(parsed, expected);
26 |
27 | Ok(())
28 | }
29 |
--------------------------------------------------------------------------------
/boilerplates/logging/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "logging"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | env_logger = "0.10.0"
10 | log = "0.4.19"
11 | run = "0.1.0"
12 |
--------------------------------------------------------------------------------
/boilerplates/logging/src/main.rs:
--------------------------------------------------------------------------------
1 | // run with env RUST_LOG=info cargo run --bin logging
2 |
3 | use log::{info, warn};
4 |
5 | fn main() {
6 | env_logger::init();
7 | info!("starting up");
8 | warn!("oops, nothing implemented!");
9 | }
10 |
--------------------------------------------------------------------------------
/boilerplates/pbkdf2/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "pbkdf2"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | data-encoding = "2.4.0"
10 | ring = "0.16.20"
11 |
--------------------------------------------------------------------------------
/boilerplates/pbkdf2/src/main.rs:
--------------------------------------------------------------------------------
1 |
2 | use data_encoding::HEXUPPER;
3 | use ring::error::Unspecified;
4 | use ring::rand::SecureRandom;
5 | use ring::{digest, pbkdf2, rand};
6 | use std::num::NonZeroU32;
7 |
8 | fn main() -> Result<(), Unspecified> {
9 | const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN;
10 | let n_iter = NonZeroU32::new(100_000).unwrap();
11 | let rng = rand::SystemRandom::new();
12 |
13 | let mut salt = [0u8; CREDENTIAL_LEN];
14 | rng.fill(&mut salt)?;
15 |
16 | let password = "Guess Me If You Can!";
17 | let mut pbkdf2_hash = [0u8; CREDENTIAL_LEN];
18 | pbkdf2::derive(
19 | pbkdf2::PBKDF2_HMAC_SHA512,
20 | n_iter,
21 | &salt,
22 | password.as_bytes(),
23 | &mut pbkdf2_hash,
24 | );
25 | println!("Salt: {}", HEXUPPER.encode(&salt));
26 | println!("PBKDF2 hash: {}", HEXUPPER.encode(&pbkdf2_hash));
27 |
28 | let should_succeed = pbkdf2::verify(
29 | pbkdf2::PBKDF2_HMAC_SHA512,
30 | n_iter,
31 | &salt,
32 | password.as_bytes(),
33 | &pbkdf2_hash,
34 | );
35 | let wrong_password = "Definitely not the correct password";
36 | let should_fail = pbkdf2::verify(
37 | pbkdf2::PBKDF2_HMAC_SHA512,
38 | n_iter,
39 | &salt,
40 | wrong_password.as_bytes(),
41 | &pbkdf2_hash,
42 | );
43 |
44 | assert!(should_succeed.is_ok());
45 | assert!(!should_fail.is_ok());
46 |
47 | Ok(())
48 | }
49 |
--------------------------------------------------------------------------------
/boilerplates/progress_bar/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "progress_bar"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | indicatif = "0.17.5"
10 |
--------------------------------------------------------------------------------
/boilerplates/progress_bar/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | let pb = indicatif::ProgressBar::new(100);
3 | for i in 0..100 {
4 | // your code here
5 | pb.println(format!("[+] finished #{}", i));
6 | pb.inc(1);
7 | }
8 | pb.finish_with_message("done");
9 | }
10 |
--------------------------------------------------------------------------------
/boilerplates/references/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "references"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/references/src/main.rs:
--------------------------------------------------------------------------------
1 | fn by_ref(x: &i32) -> i32 {
2 | *x + 1
3 | }
4 |
5 | fn modifies(x: &mut f64) {
6 | *x = 1.0;
7 | }
8 |
9 | fn main() {
10 |
11 | // simple reference
12 | let i = 10;
13 | let res1 = by_ref(&i);
14 | let res2 = by_ref(&41);
15 | println!("references are {} {}", res1,res2);
16 |
17 | // mutable reference
18 | let mut res = 4.0;
19 | modifies(&mut res);
20 | println!("references are {}", res);
21 | }
--------------------------------------------------------------------------------
/boilerplates/regex_replacing/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "regex_replacing"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | lazy_static = "1.4.0"
10 | regex = "1.9.1"
11 |
--------------------------------------------------------------------------------
/boilerplates/regex_replacing/src/main.rs:
--------------------------------------------------------------------------------
1 | use lazy_static::lazy_static;
2 |
3 | use std::borrow::Cow;
4 | use regex::Regex;
5 |
6 | fn reformat_dates(before: &str) -> Cow {
7 | lazy_static! {
8 | static ref ISO8601_DATE_REGEX : Regex = Regex::new(
9 | r"(?P\d{4})-(?P\d{2})-(?P\d{2})"
10 | ).unwrap();
11 | }
12 | ISO8601_DATE_REGEX.replace_all(before, "$m/$d/$y")
13 | }
14 |
15 | fn main() {
16 |
17 | let before = "2022-03-14, 2013-01-15 and 2014-07-05";
18 | let after = reformat_dates(before);
19 |
20 | println!("Before: {}", before);
21 | println!("After: {}", after);
22 | }
23 |
--------------------------------------------------------------------------------
/boilerplates/sha256_hash/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sha256_hash"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | data-encoding = "2.4.0"
10 | num_cpus = "1.16.0"
11 | ring = "0.16.20"
12 | threadpool = "1.8.1"
13 | walkdir = "2.3.3"
14 |
--------------------------------------------------------------------------------
/boilerplates/sha256_hash/main.rs:
--------------------------------------------------------------------------------
1 | We will generate a digest of this text
--------------------------------------------------------------------------------
/boilerplates/sha256_hash/src/main.rs:
--------------------------------------------------------------------------------
1 |
2 | use std::fs::File;
3 | use std::path::Path;
4 | use walkdir::WalkDir;
5 | use threadpool::ThreadPool;
6 | use std::sync::mpsc::channel;
7 | use data_encoding::HEXUPPER;
8 | use ring::digest::{Context, Digest, SHA256};
9 | use std::io::{BufReader, Read, Write, Error};
10 |
11 |
12 | // Verify the iso extension
13 | fn is_iso(entry: &Path) -> bool {
14 | match entry.extension() {
15 | Some(e) if e.to_string_lossy().to_lowercase() == "iso" => true,
16 | _ => false,
17 | }
18 | }
19 |
20 | fn sha256_digest>(filepath: P) -> Result<(Digest, P), Error> {
21 | let mut buf_reader = BufReader::new(File::open(&filepath)?);
22 | let mut context = Context::new(&SHA256);
23 | let mut buffer = [0; 1024];
24 |
25 | loop {
26 | let count = buf_reader.read(&mut buffer)?;
27 | if count == 0 {
28 | break;
29 | }
30 | context.update(&buffer[..count]);
31 | }
32 |
33 | Ok((context.finish(), filepath))
34 | }
35 |
36 |
37 | fn sha256_digest_file(mut reader: R) -> Result {
38 | let mut context = Context::new(&SHA256);
39 | let mut buffer = [0; 1024];
40 |
41 | loop {
42 | let count = reader.read(&mut buffer)?;
43 | if count == 0 {
44 | break;
45 | }
46 | context.update(&buffer[..count]);
47 | }
48 |
49 | Ok(context.finish())
50 | }
51 |
52 |
53 | fn main() -> Result<(), Error> {
54 |
55 | // Hash several files given a directory
56 | const DIRECTORY: &str = "/Users/m/src";
57 |
58 | let pool = ThreadPool::new(num_cpus::get());
59 | let (tx, rx) = channel();
60 |
61 | for entry in WalkDir::new(DIRECTORY)
62 | .follow_links(true)
63 | .into_iter()
64 | .filter_map(|e| e.ok())
65 | .filter(|e| !e.path().is_dir() && is_iso(e.path())) {
66 | let path = entry.path().to_owned();
67 | println!("path: {:?}", path);
68 | let tx = tx.clone();
69 | pool.execute(move || {
70 | let digest = sha256_digest(path);
71 | println!("digest: {:?}", digest);
72 | tx.send(digest).expect("Could not send data!");
73 | });
74 | }
75 |
76 | drop(tx);
77 | for t in rx.iter() {
78 | let (sha, path) = t?;
79 | println!("{:?} {:?}", sha, path);
80 | }
81 |
82 | // Hash a single file
83 | const PATH: &str = "main.rs";
84 |
85 | let mut output = File::create(PATH)?;
86 | write!(output, "We will generate a digest of this text")?;
87 |
88 | let input = File::open(PATH)?;
89 | let reader = BufReader::new(input);
90 | let digest = sha256_digest_file(reader)?;
91 |
92 | println!("SHA-256 digest is {}", HEXUPPER.encode(digest.as_ref()));
93 |
94 |
95 | Ok(())
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/boilerplates/signal_handling/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "signal_handling"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | ctrlc = "3.4.0"
10 |
--------------------------------------------------------------------------------
/boilerplates/signal_handling/src/main.rs:
--------------------------------------------------------------------------------
1 | // handles ctrl-c signal
2 |
3 | use std::{thread, time::Duration};
4 |
5 | fn main() {
6 | ctrlc::set_handler(move || {
7 | println!("received Ctrl+C!");
8 | })
9 | .expect("Error setting Ctrl-C handler");
10 |
11 | // Following code does the actual work, and can be interrupted by pressing
12 | // Ctrl-C. As an example: Let's wait a few seconds.
13 | thread::sleep(Duration::from_secs(2));
14 | }
15 |
--------------------------------------------------------------------------------
/boilerplates/tcp_ports/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "tcp_ports"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/tcp_ports/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::net::{SocketAddrV4, Ipv4Addr, TcpListener};
2 | use std::io::{Read, Error};
3 |
4 |
5 | fn main() -> Result<(), Error> {
6 |
7 | let loopback = Ipv4Addr::new(127, 0, 0, 1);
8 | let socket = SocketAddrV4::new(loopback, 0);
9 | let listener = TcpListener::bind(socket)?;
10 | let port = listener.local_addr()?;
11 |
12 | println!("Listening on {}, access this port to end the program", port);
13 |
14 | let (mut tcp_stream, addr) = listener.accept()?;
15 |
16 | println!("Connection received! {:?} is sending data.", addr);
17 |
18 | let mut input = String::new();
19 | let _ = tcp_stream.read_to_string(&mut input)?;
20 |
21 | println!("{:?} says {}", addr, input);
22 |
23 | Ok(())
24 | }
25 |
--------------------------------------------------------------------------------
/boilerplates/testing/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "testing"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/boilerplates/testing/src/main.rs:
--------------------------------------------------------------------------------
1 | // run with cargo test
2 |
3 | #[test]
4 | fn check_answer_validity() {
5 | assert_eq!(42, 42);
6 | }
7 |
8 | fn main() {
9 | println!("gm, anon!");
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/boilerplates/testing/src/test_fail.rs:
--------------------------------------------------------------------------------
1 | // run with cargo test src/test_fail.rs
2 |
3 |
4 | use assert_cmd::prelude::*;
5 | use predicates::prelude::*;
6 | use std::process::Command;
7 |
8 | #[test]
9 | fn file_doesnt_exist() -> Result<(), Box> {
10 | let mut cmd = Command::cargo_bin("grrs")?;
11 |
12 | cmd.arg("foobar").arg("test/file/doesnt/exist");
13 | cmd.assert()
14 | .failure()
15 | .stderr(predicate::str::contains("could not read file"));
16 |
17 | Ok(())
18 | }
--------------------------------------------------------------------------------
/notes/rust_async.md:
--------------------------------------------------------------------------------
1 | ## 🦀 async for rust
2 |
3 |
4 |
5 | #### on threads vs. async
6 |
7 |
8 |
9 | * the problems with threads: 1) use lots of memory, 2) launches/context switches are cost when thousands of threads are running
10 | * conversely, `async` and `await` provides concurrency, optimized hardware utilization, betters speed/performance, and lower I/O workloads.
11 |
12 |
13 |
14 |
15 | ---
16 |
17 | #### on futures
18 |
19 |
20 |
21 | * the center of async-wait is a feature called future (anything that can be computed asynchronously).
22 | * what does the keyword async in front of fn really mean?
23 |
24 |
25 |
26 |
27 |
28 | ----
29 |
30 | #### on blocking
31 |
32 |
33 |
34 | * async/await in rust is implemented using "cooperative scheduling"
35 | * a naive way to write applications is to spawn a new thread for every tasks, which works when the number of tasks is small, but doesn't scale for a large number of threads
36 | * the swap between running tasks on each thread happens with `await`: "blocking the thread" means "preventing the runtime from swapping the current tasks".
37 | * using `[tokio::spawn]` and multi-threaded runtime allow running multiple blocking tasks until you run out of threads.
38 | * the default tokio runtime spawns one thread per cpu core.
39 |
--------------------------------------------------------------------------------
/notes/rust_errors.md:
--------------------------------------------------------------------------------
1 | ## 🦀 error handling in rust
2 |
3 |
4 |
5 | * error handling in rust is different if you are coming from other languages, as it relies on `Result` and on returning instead of throwing:
6 |
7 | ```rust
8 | enum Result {
9 | Ok(T),
10 | Err(E),
11 | }
12 | ```
13 |
14 |
15 |
16 |
17 | #### ignoring the error
18 |
19 |
20 |
21 | * use `.unwrap()`:
22 |
23 | ```rust
24 | use std::fs;
25 |
26 | fn main() {
27 | let content = fs::read_to_string("./Cargo.toml").unwrap();
28 | println!("{}", content)
29 | }
30 | ```
31 |
32 |
33 |
34 | #### terminate the program
35 |
36 |
37 |
38 | * use `.unwrap()` or `.expect()` to trigger `panic!`:
39 |
40 | ```rust
41 | use std::fs;
42 |
43 | fn main() {
44 | let content = fs::read_to_string("./Cargo.toml").expect("Can't read Cargo.toml");
45 | println!("{}", content)
46 | }
47 | ```
48 |
49 |
50 |
51 | #### use a fallback value
52 |
53 |
54 |
55 | * use `.unwrap()` or `.unwrap_or()`:
56 |
57 | ```rust
58 | use std::env;
59 |
60 | fn main() {
61 | let port = env::var("PORT").unwrap_or("3000".to_string());
62 | println!("{}", port);
63 | }
64 | ```
65 |
66 |
67 |
68 |
69 | #### bubble up the error
70 |
71 | * bubble up (propagate) the error to the caller function using `?` (similar to `unwrap` but instead of panicking, it propagates the error to the calling function).
72 |
73 |
74 |
75 | ```rust
76 | use std::collections::HashMap;
77 |
78 | fn main() {
79 | match get_current_date() {
80 | Ok(date) => println!("We've time travelled to {}!!", date),
81 | Err(e) => eprintln!("Oh noes, we don't know which era we're in! :( \n {}", e),
82 | }
83 | }
84 |
85 | fn get_current_date() -> Result {
86 | let url = "https://postman-echo.com/time/object";
87 | let res = reqwest::blocking::get(url)?.json::>()?;
88 | let date = res["years"].to_string();
89 |
90 | Ok(date)
91 | }
92 | ```
93 |
94 |
95 |
96 |
97 | #### create custom errors
98 |
99 |
100 |
101 | * using the **[debug](https://doc.rust-lang.org/std/fmt/trait.Debug.html)** and **[display](https://doc.rust-lang.org/std/fmt/trait.Display.html)** traits:
102 |
103 | ```rust
104 | // error.rs
105 |
106 | // error.rs
107 |
108 | use std::fmt;
109 |
110 | #[derive(Debug)]
111 | pub enum MyCustomError {
112 | HttpError,
113 | ParseError,
114 | }
115 |
116 | impl std::error::Error for MyCustomError {}
117 |
118 | impl fmt::Display for MyCustomError {
119 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 | match self {
121 | MyCustomError::HttpError => write!(f, "HTTP Error"),
122 | MyCustomError::ParseError => write!(f, "Parse Error"),
123 | }
124 | }
125 | }
126 | ```
--------------------------------------------------------------------------------
/notes/rust_memory.md:
--------------------------------------------------------------------------------
1 | ## 🦀 memory management in rust
2 |
3 |
4 |
5 | everything starts with the algorithms basics: understanding the difference between stack and heap, the two types of memory available in runtime. when rust starts to execute, it creates a stack that keeps track of everything happening in the execution, first main(), then the following functions, etc.
6 |
7 | you might remember that stacks can’t hold too much data (and need fixed-size variables at compile time, i.e. static data types). so, for storing larger collections of variable-length data (dynamic data types), the program creates pointer references to the heap memory. also, recall that the heap is more expensive and slower, while the stack is as fast as its pointer can go.
8 |
9 | for deallocation, rust neither uses an explicit free (like c/c++) nor a garbage collection (like python). instead memory is automatically returned once the owner is out of scope - a unique feature in rust called ownership.
10 |
11 | > 💡 “in the context of a program, scope, is the range within an item is valid.”
12 |
13 |
14 |
15 |
16 |
17 | ### ownership
18 |
19 | rust’s ownership is a set of rules that the compiler checks at compile time (and that don’t slow down the program), enabling memory safety guarantees without needing garbage collection. this makes rust fast, as memory-managed languages would handle memory in runtime, but without the issues of unsafe memory errors.
20 |
21 | in rust, each given object in memory can only be handled by one variable at a time, its owner. there can only be one owner at a time. if the owner goes out of scope, the value is dropped.
22 |
23 |
24 |
25 | #### ownership is transferred by shallow copy
26 |
27 | let’s look at a very simple first example of ownership: the string type, which is allocated on the heap (as opposed to string literals, which are immutable and their values must be known at compilation).
28 |
29 | in the snippet below, we try to set the value of a string variable to a second variable. this will cause an error when println!() tries to reuse the value from the string (first variable):
30 |
31 |
32 |
33 | this would print this error (some_var lost its ownership to another_var, becoming obsolete. in c/c++, the same value would be copied to the second variable):
34 |
35 |
36 |
37 |
38 |
39 | #### ownership is kept with deep copy (although more expensive)
40 |
41 | a solution to keep some_var’s ownership would be creating a deep copy with clone(), i.e., making an explicit copy of the data by creating a second independent variable:
42 |
43 |
44 |
45 |
46 |
47 |
48 | #### the exception for integers
49 |
50 | however, rust does have some types that can be handled entirely in the stack (and so can be copied).
51 |
52 | for instance, this is the case for small values such as single integers or float points (both some_var and another_var are stack-allocated (can be copied), so this example would not cause an ownership error):
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/notes/rust_tests.md:
--------------------------------------------------------------------------------
1 | ## 🦀 writing tests in rust
2 |
3 |
4 |
5 | ### unit tests
6 |
7 |
8 |
9 | * the crates **[assert_cmd](https://docs.rs/assert_cmd)** has several helpers that makes easier, while the crate **[predicates](https://docs.rs/predicates)** helps to write assertions that can be tested against.
10 |
11 |
12 |
13 | ---
14 |
15 | ### integration tests
16 |
17 |
18 |
19 | * you want to write integrations tests for all types of behavior that a user can observe. you don't necessary need to cover all edge cases: it's usually enough to write examples for the different types and rely on unit tests for edge cases.
--------------------------------------------------------------------------------
/notes/rust_tldr.md:
--------------------------------------------------------------------------------
1 | ## 🦀 rust tl; dr
2 |
3 |
4 |
5 | ### why rust
6 |
7 | * ahead-of-time compiled language (compiling and running are separate steps).
8 | * easy control of low-level assets (such as memory usage).
9 | * better visibility for concurrency bugs.
10 |
11 |
12 |
13 | ---
14 | ### features
15 |
16 |
17 | * a `crate` is a compilation unit in Rust (i.e. `file.rs` is a crate file). it can be lib or a bin.
18 | * paths in `use` statements are relative to the current module, unless they begin with the name of a crate.
19 | * `println!` is a macro, not a function (strings are checked at compile-time)
20 | * `::` syntax indicates that the right side is an associated function of the left side (static method)
21 | * `cargo new` creates a binary; `cargo new --lib`, a library.
22 | * you can always run `cargo check` to validate your code, folder structure, etc.
23 | * you can always run `rustc --explain ` to understand errors.
24 |
25 |
26 |
27 |
28 |
29 |
30 | ---
31 | ### data structures
32 |
33 | * an array is a collection of objects of the same type T, stored in contiguous memory, represented by `[]`.
34 | * custom types are `struct` and `enum`
35 | * `From` and `Into` traits are inherently linked, providing a simple mechanism for converting between several types.
36 | * the type `HashMap` stores a mapping of keys of type `K` to values of type `V` using a hashing function.s
37 |
38 | #### variable bindings
39 |
40 | * safety via static typing (variable bindings can be type annotated when declared - and the compiler will silence warnings when vars are prefixed by `_`).
41 | * variable bindings are immutable but can be mutable with `mut` modifier.
42 |
43 | #### smart pointers
44 |
45 | * smart pointers: while references only borrow data, in many cases, smart pointers own the data they point to.
46 | * examples: `String` (stores its capacity as metadata and has the extra ability to ensure its data will always be valid UTF-8) and `Vec`.
47 | * usually implemented using structs, but unlike an ordinary struct, smart pointers implement the `Deref` and `Drop` traits.
48 | * `Deref` allows an instance of the smart pointer struct to behave like a reference so we can write code to work with either references or smart pointers.
49 | * `Drop` allows customizing the code that's run when an instance of the smart pointer goes out of scope.
50 |
51 |
52 |
53 |
54 | ---
55 |
56 | ### flow of control
57 |
58 | #### if/else
59 |
60 | ```
61 | let n = 5;
62 |
63 | if n < 0 {
64 | print!("{} is negative", n);
65 | } else if n > 0 {
66 | print!("{} is positive", n);
67 | } else {
68 | print!("{} is zero", n);
69 | }
70 | ```
71 |
72 | #### loops
73 |
74 | ```
75 | let result = loop {
76 | counter += 1;
77 |
78 | if counter == 10 {
79 | break counter * 2;
80 | }
81 | };
82 | ```
83 |
84 | #### while
85 |
86 | ```
87 | let mut n = 1;
88 | while n < 101 {
89 | if n % 15 == 0 {
90 | println!("fizzbuzz");
91 | } else if n % 3 == 0 {
92 | println!("fizz");
93 | } else if n % 5 == 0 {
94 | println!("buzz");
95 | } else {
96 | println!("{}", n);
97 | }
98 |
99 | n += 1;
100 | }
101 |
102 | ```
103 |
104 | #### for
105 |
106 | ```
107 | for n in 1..101 { // or for n in 1..=100 {
108 | if n % 15 == 0 {
109 | println!("fizzbuzz");
110 | } else if n % 3 == 0 {
111 | println!("fizz");
112 | } else if n % 5 == 0 {
113 | println!("buzz");
114 | } else {
115 | println!("{}", n);
116 | }
117 | }
118 | ```
119 |
120 | #### match
121 |
122 | * same pattern as C's `switch`:
123 |
124 | ```
125 | match number {
126 | 1 => println!("One!"),
127 | 2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
128 | 13..=19 => println!("A teen"),
129 | _ => println!("no matchl"),
130 | }
131 |
132 | ```
133 |
134 | * a `match` guard can be added to filter the arm.
135 | * a `match` block can [destructure items in a variety of ways](https://doc.rust-lang.org/rust-by-example/flow_control/match/destructuring.html).
136 |
137 | #### expressions
138 |
139 | * blocks are expressions: they can be used as values in assignments.
140 | * the last expression in the block will be assigned to the place expression, such as a local variable if no `;`, otherwise the return value will be `()`.
141 |
142 |
143 |
144 | ---
145 |
146 | ### functions
147 |
148 |
149 | #### associated functions
150 |
151 | * methods are associated functions that are called on a particular instance of a type.
152 | * associated functions are functions that are defined on a type generally (like constructors):
153 |
154 | ```
155 | struct Point {
156 | x: f64,
157 | y: f64,
158 | }
159 |
160 | impl Point {
161 | fn origin() -> Point {
162 | Point { x: 0.0, y: 0.0 }
163 | }
164 |
165 | fn new(x: f64, y: f64) -> Point {
166 | Point { x: x, y: y }
167 | }
168 | }
169 | ```
170 |
171 | #### [closure](https://doc.rust-lang.org/rust-by-example/fn/closures/anonymity.html)
172 |
173 | * calling a closure is exactly like calling a function. however, both input and return types can be inferred and input variable names must be specified.
174 | * `||` instead of `()` around input variables.
175 | * closures are anonymous.
176 |
177 | ```
178 | let closure_annotated = |i: i32| -> i32 { i + 1 };
179 | ```
180 |
181 | * closures can capture variables:
182 | - by reference: `&T`
183 | - by mutable reference: `&mut T`
184 | - by value: `T`
185 |
186 | * when taking closure as input parameters, the closure's complete type must be annotated:
187 | - `Fn`: the closure uses the captured value by reference (`&T`).
188 | - `FnMut`: the closure uses the captured value by mutable reference (`&mut T`).
189 | - `FnOnce`: the closure uses the captured value by value (`T`).
190 |
191 | #### diverging functions
192 |
193 | * diverging functions never return.
194 | * they are marked using `!`, which is an empty type:
195 |
196 | ```
197 | fn foo() -> ! {
198 | panic!("This call never returns.");
199 | }
200 | ```
201 |
202 |
203 |
204 | ---
205 | ### modules
206 |
207 | * a module is a collection of items: functions, structs, traits, `impl` blocks, and other modules.
208 | * only public items of a module can be accessed from outside the module scope.
209 | * `use` declaration can be used to bind a full path to a new name, for easer access.
210 | * the `super` and `self` keywords can be used in the path to remove ambiguity when accessing items.
211 | * [(OMG file hierarchy in rust is poetry 🖤)](https://doc.rust-lang.org/rust-by-example/mod/split.html).
212 |
213 |
214 |
215 | ---
216 | ### generics
217 |
218 | * a type parameter is specified as generic by the use of angle brackets and upper camel cases (``).
219 | * traits are similar to a feature often called interfaces in other languages, although with some differences.
220 | * every reference in rust has a lifetime, which is the scope for which the reference is valid.
221 |
222 |
223 |
224 | ---
225 |
226 | ### memory
227 |
228 | * memory in rust is managed through a system of ownership with a set of rules that the compiler checks.
229 | * in rust, a value is either on the stack (LIFO, faster) on the heap (linked list, slower).
230 | * The `String` type is stored on the heap.
231 | * No garbage collector, the memory is automatically returned once the variable that owns it goes out of scope.
232 |
233 |
234 |
235 |
236 | ---
237 | ### projects
238 |
239 | * a crate is the smallest amount of code that the compiler considers at time.
240 | * a package can contain multiple binary crates and optionally one library crate. each binary must have a `main` function. library crates don't have a `main` function.
241 | * most of the times when we say "crate" we mean library crate.
242 | * a package is a bundle of one or more crates that provide a set of functionality, and contains a `Cargo.toml` describing how to build the crates.
243 | * when compiling a crate, the compiler first looks in the crate root file (usually src/lib.rs for a library crate or src/main.rs for a binary crate) for code to compile.
244 | * in the crate root file, if you declare a "garden" with `mod garden`, the compiler looks for:
245 | - inline, within curly brackets that replace the semicolon following `mod garden`
246 | - in the file `src/garden.rs`
247 | - in the file `src/garden/mod.rs`
248 |
249 |
250 |
251 | ---
252 |
253 | ### concurrency
254 |
255 |
256 | * concurrency: different parts of a program execute independently. parallel programming: different parts of a program execute at the same time.
257 | * ownership and type system are a set of tools to help manage memory safety and concurrency problems/bugs.
258 | * to accomplish message-sending concurrency, Rust's standard library provides `channels`. a channel is a concept by which data is sent from one thread to another.
259 |
--------------------------------------------------------------------------------
/notes/rust_tricks.md:
--------------------------------------------------------------------------------
1 | ## 🦀 some good tricks when writing rust (ongoing)
2 |
3 |
4 |
5 | #### packages
6 |
7 | * if you are testing a published crate locally, you can build with `make build` and then run the binary from `./targets/debug/`
8 |
9 |
10 |
11 | ##### `Some()`
12 |
13 | * `Option::as_deref` converts `&Option>` into `Option<&[T]>`
14 | * `unwrap_or_default` returns `&[T]`
15 |
--------------------------------------------------------------------------------
/w3kit/.env.example:
--------------------------------------------------------------------------------
1 | ##################
2 | ## PROVIDER URLS #
3 | ##################
4 |
5 | ARBITRUM_URL_WS=
6 | ARBITRUM_URL_HTTP=
7 | AVALANCHE_URL_WS=
8 | AVALANCHE_URL_HTTP=
9 | ETHEREUM_URL_WS=
10 | ETHEREUM_URL_HTTP=
11 | NEAR_URL_WS=
12 | NEAR_URL_HTTP=
13 | OPTIMISM_URL_WS=
14 | OPTIMISM_URL_HTTP=
15 | POLYGON_URL_WS=
16 | POLYGON_URL_HTTP=
17 | SOLANA_URL_WS=
18 | SOLANA_URL_HTTP=
19 |
20 | ##################
21 | ## DATA #
22 | ##################
23 |
24 | COINGECKO_API_URL="https://api.coingecko.com/api/v3/"
25 |
26 |
--------------------------------------------------------------------------------
/w3kit/Cargo.toml:
--------------------------------------------------------------------------------
1 |
2 | [package]
3 | name = "w3kit"
4 | version = "0.1.5"
5 | edition = "2021"
6 | license = "MIT"
7 | description="A toolkit for several blockchains."
8 |
9 | [dependencies]
10 | reqwest = "0.11.10"
11 | web3 = "0.18.0"
12 | dotenv = "0.15.0"
13 | serde = { version="1.0.144", features=["derive"] }
14 | serde_json = "1.0.72"
15 | clap = { version = "4.1.4", features = ["derive"] }
16 | ethers = {version = "1.0.2", git = "https://github.com/gakonst/ethers-rs", features = ["ws", "rustls", "abigen"] }
17 | tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
18 | tiny-keccak = { version = "2.0.2", features = ["keccak"] }
19 | rust-bybit = { version = "0.1.0-alpha.0", git = "https://github.com/yufuquant/rust-bybit.git" }
20 |
21 |
--------------------------------------------------------------------------------
/w3kit/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build
2 | build:
3 | cargo build
4 |
5 | .PHONY: run
6 | run:
7 | cargo run
8 |
9 | .PHONY: check
10 | check:
11 | cargo check
12 |
13 | .PHONY: clean
14 | clean:
15 | cargo clean
16 |
17 | .PHONY: install
18 | install:
19 | cargo install
20 |
21 | .PHONY: publish
22 | publish:
23 | cargo publish --allow-dirty
24 |
25 | .PHONY: pkglist
26 | pkglist:
27 | cargo package --list
28 |
29 | .PHONY: login
30 | login:
31 | cargo login
32 |
33 |
--------------------------------------------------------------------------------
/w3kit/README.md:
--------------------------------------------------------------------------------
1 | ## 🕹 w3kit: a web3 toolkit in rust
2 |
3 |
4 | ### tl;dr
5 |
6 |
7 |
8 | ##### 🛠 **[this package](https://github.com/go-outside-labs/web3-toolkit-rs/tree/main/w3kit)** contains an ongoing crate with a set of scripts for several blockchains (check it at **[crates.io](https://crates.io/crates/w3kit)**).
9 |
10 | ##### 💡 for a rusty boilerplate for running stat searchers, check **[coingator](https://github.com/go-outside-labs/searcher-coingator-rs)**.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ---
25 |
26 | ### installation
27 |
28 |
29 |
30 |
31 | #### as a package
32 |
33 |
34 |
35 |
36 | ```
37 | cargo install w3kit
38 | ```
39 |
40 |
41 |
42 | #### for development
43 |
44 |
45 |
46 | to build the library from this [GitHub repository](https://github.com/go-outside-labs/web3-toolkit-rs/tree/main/w3kit) you can run:
47 |
48 | ```
49 | make build
50 | ```
51 |
52 |
53 |
54 | note that all [cargo](https://doc.rust-lang.org/cargo/) commands relevant to this work are encoded in the `Makefile`.
55 |
56 |
57 |
58 |
59 |
60 | #### setup
61 |
62 |
63 |
64 | create an `.env` file:
65 |
66 | ```
67 | cp .env.example .env
68 | vim .env
69 | ```
70 |
71 | then add the config for the desired chain:
72 |
73 | ```
74 | PROVIDER_URL_WS=
75 | PROVIDER_URL_HTTP=
76 | ```
77 |
78 |
79 |
80 | ----
81 |
82 | ### ethereum
83 |
84 |
85 |
86 | #### connection to the chain
87 |
88 |
89 |
90 | ###### through an http connection:
91 |
92 | ```
93 | > w3kit http -b ethereum
94 |
95 | ✅ connecting to "ethereum"
96 | ✅ current block: 16572583
97 | ```
98 |
99 |
100 | ###### through a websocket connection:
101 |
102 | ```
103 | > w3kit ws -b ethereum
104 |
105 | ✅ connecting to "ethereum"
106 | ✅ current block: 16572598
107 | ```
108 |
109 |
110 |
111 | #### retrieving an account data
112 |
113 |
114 | ```
115 | > w3kit account -b ethereum -a 0xbA4C081942E6a25cAF87c5489B91b449c67f3078
116 |
117 | ✅ connecting to "ethereum"
118 | ✅ fetching account info: "0xbA4C081942E6a25cAF87c5489B91b449c67f3078"
119 | ✅ retrieving balances...
120 | 💰 account 0xba4c081942e6a25caf87c5489b91b449c67f3078 👉 0.0672775267238201 ETH
121 | ```
122 |
123 |
124 |
125 |
126 | ---
127 |
128 | ### market
129 |
130 |
131 |
132 | #### retrieving a coin price
133 |
134 | this tool leverages [coingecko api](https://www.coingecko.com/en/api/documentation) for coin info. other markets might be added later.
135 |
136 | ```
137 | > w3kit coin ethereum
138 |
139 | ✅ fetching marketcap for ethereum
140 | ✅ GET https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd&include_market_cap=true
141 | 🪙 price 👉 $1625.35
142 | 📊 marketcap 👉 195950687355.82028
143 | ```
144 |
145 |
146 |
147 |
148 | ---
149 |
150 | ### arbitrum
151 |
152 |
153 |
154 |
155 | #### connection to the chain
156 |
157 |
158 |
159 | ###### through an http connection:
160 |
161 | ```
162 | > w3kit http -b arbitrum
163 | ```
164 |
165 |
166 |
167 | ###### through a websocket connection:
168 |
169 | ```
170 | > w3kit ws -b arbitrum
171 | ```
172 |
173 |
174 |
175 | #### retrieving an account data
176 |
177 |
178 | ```
179 | > w3kit account -b arbitrum -a
180 | ```
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 | ---
189 |
190 | ### avalanche
191 |
192 |
193 |
194 |
195 | #### connection to the chain
196 |
197 |
198 |
199 | ###### through an http connection:
200 |
201 | ```
202 | > w3kit http -b avalanche
203 | ```
204 |
205 |
206 |
207 | ###### through a websocket connection:
208 |
209 | ```
210 | > w3kit ws -b avalanche
211 | ```
212 |
213 |
214 |
215 | #### retrieving an account data
216 |
217 |
218 | ```
219 | > w3kit account -b avalanche -a
220 | ```
221 |
222 |
223 |
224 |
225 |
226 | ---
227 |
228 | ### near
229 |
230 |
231 |
232 |
233 | #### connection to the chain
234 |
235 |
236 |
237 | ###### through an http connection:
238 |
239 | ```
240 | > w3kit http -b near
241 | ```
242 |
243 |
244 |
245 | ###### through a websocket connection:
246 |
247 | ```
248 | > w3kit ws -b near
249 | ```
250 |
251 |
252 |
253 | #### retrieving an account data
254 |
255 |
256 | ```
257 | > w3kit account -b near -a
258 | ```
259 |
260 |
261 |
262 |
263 | ---
264 |
265 | ### optimism
266 |
267 |
268 |
269 |
270 | #### connection to the chain
271 |
272 |
273 |
274 | ###### through an http connection:
275 |
276 | ```
277 | > w3kit http -b optimism
278 | ```
279 |
280 |
281 |
282 | ###### through a websocket connection:
283 |
284 | ```
285 | > w3kit ws -b optimism
286 | ```
287 |
288 |
289 |
290 |
291 | #### retrieving an account data
292 |
293 |
294 | ```
295 | > w3kit account -b optimism -a
296 | ```
297 |
298 |
299 |
300 | ---
301 |
302 | ### polygon
303 |
304 |
305 |
306 |
307 | #### connection to the chain
308 |
309 |
310 |
311 | ###### through an http connection:
312 |
313 | ```
314 | > w3kit http -b polygon
315 | ```
316 |
317 |
318 |
319 | ###### through a websocket connection:
320 |
321 | ```
322 | > w3kit ws -b polygon
323 | ```
324 |
325 |
326 |
327 | #### retrieving an account data
328 |
329 |
330 | ```
331 | > w3kit account -b polygon -a
332 | ```
333 |
334 |
335 |
336 |
337 | ---
338 |
339 | ### solana
340 |
341 |
342 |
343 |
344 | #### connection to the chain
345 |
346 |
347 |
348 | ###### through an http connection:
349 |
350 | ```
351 | > w3kit http -b solana -a
352 | ```
353 |
354 |
355 |
356 | ###### through a websocket connection:
357 |
358 | ```
359 | > w3kit ws -b solana -a
360 | ```
361 |
362 |
363 |
364 | #### retrieving an account data
365 |
366 |
367 | ```
368 | > w3kit account -b solana -a
369 | ```
370 |
371 |
372 |
373 |
--------------------------------------------------------------------------------
/w3kit/src/arbitrum/connector.rs:
--------------------------------------------------------------------------------
1 | // arbitrum/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 |
7 | ////////////////////////////
8 | // Public functions
9 | ////////////////////////////
10 |
11 | pub async fn arbitrum_connect_ws() {
12 |
13 | let url = &env::var("ARBITRUM_URL_WS").expect("⛔️ No ARBITRUM_URL_WS on .env file");
14 | println!("⛔️ arbitrum_connect_ws() not implemented yet");
15 |
16 | }
17 |
18 | pub async fn arbitrum_connect_http() {
19 |
20 | let url = &env::var("ARBITRUM_URL_HTTP").expect("⛔️ No ARBITRUM_URL_HTTP on .env file");
21 | println!("⛔️ arbitrum_connect_http() not implemented yet");
22 |
23 | }
24 |
25 | pub async fn arbitrum_get_account(account_address: &str) {
26 |
27 | println!("⛔️ arbitrum_get_account() not implemented yet");
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/w3kit/src/arbitrum/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{arbitrum_connect_ws,
4 | arbitrum_connect_http,
5 | arbitrum_get_account};
--------------------------------------------------------------------------------
/w3kit/src/avalanche/connector.rs:
--------------------------------------------------------------------------------
1 | // avalanche/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 |
7 | ////////////////////////////
8 | // Public functions
9 | ////////////////////////////
10 |
11 | pub async fn avalanche_connect_ws() {
12 |
13 | let url = &env::var("AVALANCHE_URL_WS").expect("⛔️ No AVALANCHE_URL_WS on .env file");
14 | println!("⛔️ avalanche_connect_ws() not implemented yet");
15 |
16 | }
17 |
18 | pub async fn avalanche_connect_http() {
19 |
20 | let url = &env::var("AVALANCHE_URL_HTTP").expect("⛔️ No AVALANCHE_URL_HTTP on .env file");
21 | println!("⛔️ avalanche_connect_http() not implemented yet");
22 |
23 | }
24 |
25 | pub async fn avalanche_get_account(account_address: &str) {
26 |
27 | println!("⛔️ avalanche_get_account() not implemented yet");
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/w3kit/src/avalanche/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{avalanche_connect_ws,
4 | avalanche_connect_http,
5 | avalanche_get_account};
--------------------------------------------------------------------------------
/w3kit/src/dexs/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod uniswap;
2 |
3 |
--------------------------------------------------------------------------------
/w3kit/src/dexs/uniswapv2.rs:
--------------------------------------------------------------------------------
1 | // dexs/uniswapv2.rs
2 |
--------------------------------------------------------------------------------
/w3kit/src/ethereum/connector.rs:
--------------------------------------------------------------------------------
1 | // ethereum/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::str::FromStr;
5 | use web3::types::{H160};
6 |
7 | pub type Transport = web3::transports::Either;
8 |
9 | use crate::{
10 | utils::maths::wei_to_eth,
11 | };
12 |
13 |
14 | ////////////////////////////
15 | // Private methods
16 | ////////////////////////////
17 |
18 | async fn get_account(transport: Transport, account_address: &str) -> web3::Result<()> {
19 |
20 | let web3s = web3::Web3::new(transport);
21 |
22 | let mut accounts = web3s.eth().accounts().await?;
23 | accounts.push(H160::from_str(account_address).unwrap());
24 | println!("✅ retrieving balances...");
25 |
26 | for account in accounts {
27 | let balance = web3s.eth().balance(account, None).await?;
28 | println!(" 💰 account {:?} 👉 {} ETH", account, wei_to_eth(balance));
29 | }
30 |
31 | Ok(())
32 |
33 | }
34 |
35 | async fn get_block(transport: Transport) -> web3::Result<()> {
36 |
37 | let web3s = web3::Web3::new(transport);
38 |
39 | let block = web3s.eth().block_number().await?;
40 | println!("✅ current block: {:?}", block);
41 |
42 | Ok(())
43 |
44 | }
45 |
46 |
47 | ////////////////////////////
48 | // Public methods
49 | ////////////////////////////
50 |
51 | // This function connects to Ethereum via either HTTP or WS
52 | pub async fn ethereum_connect(provider_url: &str) -> web3::Result {
53 |
54 | let transport = web3::transports::Http::new(provider_url)?;
55 |
56 | get_block(web3::transports::Either::Right(transport)).await
57 |
58 | }
59 |
60 |
61 | pub async fn ethereum_get_account(provider_url: &str, account_address: &str) -> web3::Result {
62 |
63 | let transport = web3::transports::Http::new(provider_url)?;
64 |
65 | get_account(web3::transports::Either::Right(transport), account_address).await
66 |
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/w3kit/src/ethereum/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{ethereum_connect,
4 | ethereum_get_account};
5 |
--------------------------------------------------------------------------------
/w3kit/src/main.rs:
--------------------------------------------------------------------------------
1 | // src/utils/commands.rs
2 | // author: steinkirch
3 |
4 | mod utils;
5 | mod market;
6 | mod ethereum;
7 | mod arbitrum;
8 | mod avalanche;
9 | mod optimism;
10 | mod near;
11 | mod polygon;
12 | mod solana;
13 |
14 | use clap::Parser;
15 |
16 | use utils::{CliEnum,
17 | CliStruct,
18 | handle_ws,
19 | handle_http,
20 | handle_account,
21 | handle_coin};
22 |
23 | #[tokio::main]
24 | async fn main() {
25 |
26 | dotenv::dotenv().ok();
27 | let args = CliStruct::parse();
28 |
29 | match args.command {
30 | CliEnum::Ws(args) => handle_ws(args).await,
31 | CliEnum::Http(args) => handle_http(args).await,
32 | CliEnum::Account(args) => handle_account(args).await,
33 | CliEnum::Coin(args) => handle_coin(args).await,
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/w3kit/src/market/coingecko.rs:
--------------------------------------------------------------------------------
1 | // market/coingecko.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 | use serde_json;
6 |
7 |
8 | ////////////////////////////
9 | // Private functions
10 | ////////////////////////////
11 |
12 | async fn get_request(url: &str) -> serde_json::Value {
13 |
14 | println!("✅ GET {}", url);
15 | let response = reqwest::get(url)
16 | .await.unwrap()
17 | .json::()
18 | .await.unwrap();
19 |
20 | if response["error"].is_string() {
21 | println!("⛔️ {}", response["error"]);
22 | std::process::exit(1);
23 | }
24 |
25 | return response
26 |
27 | }
28 |
29 |
30 | #[allow(dead_code)]
31 | async fn coin_price(coin: &str, currency: &str) {
32 |
33 | println!("✅ fetching price for {} in {}", coin, currency);
34 |
35 | let coingecko_url = &env::var("COINGECKO_API_URL").expect("⛔️ No COINGECKO_API_URL on .env file");
36 | let url = format!("{}simple/price?ids={}&vs_currencies={}", coingecko_url, coin, currency);
37 |
38 | let coin_price = get_request(&url).await;
39 | println!(" 🪙 {} price 👉 {}", coin, coin_price);
40 | }
41 |
42 |
43 | async fn coin_marketcap(coin: &str, currency: &str) {
44 |
45 | println!("✅ fetching marketcap for {}", coin);
46 |
47 | let coingecko_url = &env::var("COINGECKO_API_URL").expect("⛔️ No COINGECKO_API_URL on .env file");
48 | let url = format!("{}simple/price?ids={}&vs_currencies={}&include_market_cap=true", coingecko_url, coin, currency);
49 |
50 | let coin_marketcap = get_request(&url).await;
51 |
52 | println!(" 🪙 price 👉 ${}", coin_marketcap[coin][currency]);
53 | println!(" 📊 marketcap 👉 {}", coin_marketcap[coin]["usd_market_cap"]);
54 | }
55 |
56 |
57 | ////////////////////////////
58 | // Public functions
59 | ////////////////////////////
60 |
61 |
62 | pub async fn get_coin_info(coin_name: &str) {
63 |
64 | // TODO: add support for multiple currencies
65 | let currency = "usd";
66 |
67 | coin_marketcap(coin_name, currency).await;
68 |
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/w3kit/src/market/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod coingecko;
2 |
3 |
4 | pub use coingecko::{get_coin_info};
5 |
6 |
--------------------------------------------------------------------------------
/w3kit/src/near/connector.rs:
--------------------------------------------------------------------------------
1 | // near/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 |
7 | ////////////////////////////
8 | // Public functions
9 | ////////////////////////////
10 |
11 | pub async fn near_connect_ws() {
12 |
13 | let url = &env::var("NEAR_URL_WS").expect("⛔️ No NEAR_URL_WS on .env file");
14 | println!("⛔️ near_connect_ws() not implemented yet");
15 |
16 | }
17 |
18 | pub async fn near_connect_http() {
19 |
20 | let url = &env::var("NEAR_URL_HTTP").expect("⛔️ No NEAR_URL_HTTP on .env file");
21 | println!("⛔️ near_connect_http() not implemented yet");
22 |
23 | }
24 |
25 | pub async fn near_get_account(account_address: &str) {
26 |
27 | println!("✅ retrieving balances...");
28 | println!("⛔️ near_get_account() not implemented yet");
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/w3kit/src/near/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{near_connect_ws,
4 | near_connect_http,
5 | near_get_account};
--------------------------------------------------------------------------------
/w3kit/src/optimism/connector.rs:
--------------------------------------------------------------------------------
1 | // optimism/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 |
7 |
8 | ////////////////////////////
9 | // Public functions
10 | ////////////////////////////
11 |
12 | pub async fn optimism_connect_ws() {
13 |
14 | let url = &env::var("OPTIMISM_URL_WS").expect("⛔️ No OPTIMISM_URL_WS on .env file");
15 | println!("⛔️ optimism_connect_ws() not implemented yet");
16 |
17 | }
18 |
19 | pub async fn optimism_connect_http() {
20 |
21 | let url = &env::var("OPTIMISM_URL_HTTP").expect("⛔️ No OPTIMISM_URL_HTTP on .env file");
22 | println!("⛔️ optimism_connect_http() not implemented yet");
23 |
24 | }
25 |
26 | pub async fn optimism_get_account(account_address: &str) {
27 |
28 | println!("⛔️ optimism_get_account() not implemented yet");
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/w3kit/src/optimism/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{optimism_connect_ws,
4 | optimism_connect_http,
5 | optimism_get_account};
--------------------------------------------------------------------------------
/w3kit/src/polygon/connector.rs:
--------------------------------------------------------------------------------
1 | // polygon/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 |
7 |
8 | ////////////////////////////
9 | // Public functions
10 | ////////////////////////////
11 |
12 | pub async fn polygon_connect_ws() {
13 |
14 | let url = &env::var("POLYGON_URL_WS").expect("⛔️ No POLYGON_URL_WS on .env file");
15 | println!("⛔️ polygon_connect_ws() not implemented yet");
16 |
17 | }
18 |
19 | pub async fn polygon_connect_http() {
20 |
21 | let url = &env::var("POLYGON_URL_HTTP").expect("⛔️ No POLYGON_URL_HTTP on .env file");
22 | println!("⛔️ polygon_connect_http() not implemented yet");
23 |
24 | }
25 |
26 | pub async fn polygon_get_account(account_address: &str) {
27 |
28 | println!("⛔️ polygon_get_account() not implemented yet");
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/w3kit/src/polygon/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{polygon_connect_ws,
4 | polygon_connect_http,
5 | polygon_get_account};
--------------------------------------------------------------------------------
/w3kit/src/solana/connector.rs:
--------------------------------------------------------------------------------
1 | // solana/connectors.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 |
7 | ////////////////////////////
8 | // Public functions
9 | ////////////////////////////
10 |
11 | pub async fn solana_connect_ws() {
12 |
13 | let url = &env::var("SOLANA_URL_WS").expect("⛔️ No SOLANA_URL_WS on .env file");
14 | println!("⛔️ solana_connect_ws() not implemented yet");
15 |
16 | }
17 |
18 | pub async fn solana_connect_http() {
19 |
20 | let url = &env::var("SOLANA_URL_HTTP").expect("⛔️ No SOLANA_URL_HTTP on .env file");
21 | println!("⛔️ solana_connect_http() not implemented yet");
22 |
23 | }
24 |
25 | pub async fn solana_get_account(account_address: &str) {
26 |
27 | println!("⛔️ solana_get_account() not implemented yet");
28 |
29 | }
30 |
31 |
32 |
--------------------------------------------------------------------------------
/w3kit/src/solana/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod connector;
2 |
3 | pub use connector::{solana_connect_ws,
4 | solana_connect_http,
5 | solana_get_account};
--------------------------------------------------------------------------------
/w3kit/src/utils/cli_handler.rs:
--------------------------------------------------------------------------------
1 | // src/utils/cli_handler.rs
2 | // author: steinkirch
3 |
4 | use std::env;
5 |
6 | use crate::{
7 | utils::commands::{ConnectionArgs,
8 | AccountArgs,
9 | CoinArgs},
10 | ethereum::connector::{ethereum_connect,
11 | ethereum_get_account},
12 | arbitrum::connector::{arbitrum_connect_ws,
13 | arbitrum_get_account,
14 | arbitrum_connect_http},
15 | avalanche::connector::{avalanche_connect_ws,
16 | avalanche_get_account,
17 | avalanche_connect_http},
18 | optimism::connector::{optimism_connect_ws,
19 | optimism_get_account,
20 | optimism_connect_http},
21 | near::connector::{near_connect_ws,
22 | near_get_account,
23 | near_connect_http},
24 | polygon::connector::{polygon_connect_ws,
25 | polygon_get_account,
26 | polygon_connect_http},
27 | solana::connector::{solana_connect_ws,
28 | solana_get_account,
29 | solana_connect_http},
30 | market::coingecko::{get_coin_info},
31 | };
32 |
33 | /////////////////////////////////////////
34 | // Public functions
35 | /////////////////////////////////////////
36 |
37 | // Note: these methods will be refactored once
38 | // more specific connectors are implemented
39 |
40 | pub async fn handle_ws(args: ConnectionArgs) {
41 |
42 | let blockchain = &args.blockchain.to_string();
43 |
44 | println!("✅ connecting to {:?}", blockchain);
45 |
46 | match String::from(blockchain).as_str() {
47 |
48 | "arbitrum" => arbitrum_connect_ws().await,
49 | "avalanche" => avalanche_connect_ws().await,
50 | "optimism" => optimism_connect_ws().await,
51 | "near" => near_connect_ws().await,
52 | "polygon" => polygon_connect_ws().await,
53 | "solana" => solana_connect_ws().await,
54 | "ethereum" => {
55 | let url = &env::var("ETHEREUM_URL_WS").expect("⛔️ No ETHEREUM_URL_WS on .env file");
56 | match ethereum_connect(url).await {
57 | Err(e) => println!("⛔️ {:?}", e),
58 | _ => ()
59 | }
60 | }
61 | &_ => todo!()
62 | }
63 | }
64 |
65 |
66 | pub async fn handle_http(args: ConnectionArgs) {
67 |
68 | let blockchain = &args.blockchain.to_string();
69 |
70 | println!("✅ connecting to {:?}", blockchain);
71 |
72 | match String::from(blockchain).as_str() {
73 |
74 | "arbitrum" => arbitrum_connect_http().await,
75 | "avalanche" => avalanche_connect_http().await,
76 | "optimism" => optimism_connect_http().await,
77 | "near" => near_connect_http().await,
78 | "polygon" => polygon_connect_http().await,
79 | "solana" => solana_connect_http().await,
80 | "ethereum" => {
81 | let url = &env::var("ETHEREUM_URL_HTTP").expect("⛔️ No ETHEREUM_URL_HTTP on .env file");
82 | match ethereum_connect(url).await {
83 | Err(e) => println!("⛔️ {:?}", e),
84 | _ => ()
85 | }
86 | }
87 | &_ => todo!()
88 | }
89 | }
90 |
91 |
92 | pub async fn handle_account(args: AccountArgs) {
93 |
94 | let blockchain = &args.blockchain.to_string();
95 | let account = &args.account.to_string();
96 |
97 | println!("✅ connecting to {:?}", blockchain);
98 | println!("✅ fetching account info: {:?}", account);
99 |
100 | match String::from(blockchain).as_str() {
101 |
102 | "arbitrum" => arbitrum_get_account(account).await,
103 | "avalanche" => avalanche_get_account(account).await,
104 | "optimism" => optimism_get_account(account).await,
105 | "near" => near_get_account(account).await,
106 | "polygon" => polygon_get_account(account).await,
107 | "solana" => solana_get_account(account).await,
108 | "ethereum" => {
109 | let url = &env::var("ETHEREUM_URL_HTTP").expect("⛔️ No ETHEREUM_URL_HTTP on .env file");
110 | match ethereum_get_account(url, account).await {
111 | Err(e) => println!("⛔️ {:?}", e),
112 | _ => ()
113 | }
114 | }
115 | &_ => todo!()
116 | }
117 | }
118 |
119 |
120 | pub async fn handle_coin(args: CoinArgs) {
121 |
122 | let coin = &args.coin.to_string();
123 | get_coin_info(coin).await;
124 |
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/w3kit/src/utils/commands.rs:
--------------------------------------------------------------------------------
1 | // src/utils/commands.rs
2 | // author: steinkirch
3 |
4 | use clap::{Args, Parser, Subcommand};
5 |
6 |
7 | #[derive(Debug, Parser)]
8 | #[clap(name = "w3kit")]
9 | #[clap(about = "🕹✨ a rusty toolkit for several blockchains ✨🕹")]
10 | pub struct CliStruct {
11 | #[clap(subcommand)]
12 | pub command: CliEnum,
13 | }
14 |
15 |
16 | #[derive(Debug, Subcommand)]
17 | pub enum CliEnum {
18 | #[clap(arg_required_else_help = true)]
19 | /// Test a websocket connection to a given blockchain
20 | Ws(ConnectionArgs),
21 | #[clap(arg_required_else_help = true)]
22 | /// Test an http connection to a given blockchain
23 | Http(ConnectionArgs),
24 | #[clap(arg_required_else_help = true)]
25 | /// Get an account balance from a given blockchain
26 | Account(AccountArgs),
27 | #[clap(arg_required_else_help = true)]
28 | /// Get a coin price and market cap
29 | Coin(CoinArgs),
30 | }
31 |
32 |
33 | #[derive(Debug, Args)]
34 | pub struct ConnectionArgs {
35 | #[clap(short, long)]
36 | /// The blockchain to connect to
37 | pub blockchain: String,
38 | }
39 |
40 |
41 | #[derive(Debug, Args)]
42 | pub struct AccountArgs {
43 | #[clap(short, long)]
44 | /// The blockchain to connect to
45 | pub blockchain: String,
46 | #[clap(short, long)]
47 | /// The account to be fetched
48 | pub account: String,
49 | }
50 |
51 |
52 | #[derive(Debug, Args)]
53 | pub struct CoinArgs {
54 | /// The coin to get info about
55 | pub coin: String,
56 | }
57 |
--------------------------------------------------------------------------------
/w3kit/src/utils/maths.rs:
--------------------------------------------------------------------------------
1 | // src/utils/maths.rs
2 | // author: steinkirch
3 |
4 |
5 | use web3::types::{U256};
6 | use tiny_keccak::{Hasher, Keccak};
7 |
8 |
9 | // Simple function to convert wei to eth
10 | pub fn wei_to_eth(wei_val: U256) -> f64 {
11 |
12 | let res = wei_val.as_u128() as f64;
13 | res / 1_000_000_000_000_000_000.0
14 |
15 | }
16 |
17 | /// Compute the Keccak-256 hash of input bytes
18 | #[allow(dead_code)]
19 | pub fn keccak256(bytes: &[u8]) -> [u8; 32] {
20 |
21 | let mut output = [0u8; 32];
22 | let mut hasher = Keccak::v256();
23 |
24 | hasher.update(bytes);
25 | hasher.finalize(&mut output);
26 |
27 | output
28 | }
--------------------------------------------------------------------------------
/w3kit/src/utils/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod maths;
2 | pub mod commands;
3 | pub mod cli_handler;
4 |
5 | pub use commands::{CliEnum,
6 | CliStruct};
7 | pub use maths::{wei_to_eth,
8 | keccak256};
9 | pub use cli_handler::{handle_ws,
10 | handle_http,
11 | handle_account,
12 | handle_coin};
13 |
--------------------------------------------------------------------------------