Skip to content

Commit 2bec42b

Browse files
committed
Ingress proxy version
1 parent c556df9 commit 2bec42b

File tree

8 files changed

+301
-0
lines changed

8 files changed

+301
-0
lines changed

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, prototype ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
check:
14+
name: Check
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: dtolnay/rust-toolchain@stable
19+
- run: cargo check
20+
21+
test:
22+
name: Test
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: actions/checkout@v4
26+
- uses: dtolnay/rust-toolchain@stable
27+
- run: cargo test
28+
29+
fmt:
30+
name: Rustfmt
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v4
34+
- uses: dtolnay/rust-toolchain@stable
35+
with:
36+
components: rustfmt
37+
- run: cargo fmt --all -- --check
38+
39+
clippy:
40+
name: Clippy
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@v4
44+
- uses: dtolnay/rust-toolchain@stable
45+
with:
46+
components: clippy
47+
- run: cargo clippy -- -D warnings
48+
49+
build:
50+
name: Build
51+
runs-on: ubuntu-latest
52+
steps:
53+
- uses: actions/checkout@v4
54+
- uses: dtolnay/rust-toolchain@stable
55+
- run: cargo build --release

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Rust
2+
/target/
3+
Cargo.lock
4+
5+
# IDE
6+
.idea/
7+
.vscode/
8+
*.swp
9+
*.swo
10+
11+
# OS
12+
.DS_Store
13+
Thumbs.db
14+
15+
# Logs
16+
*.log
17+
18+
# Environment variables
19+
.env
20+
.env.local
21+
22+
# Backup files
23+
*~
24+
*.bak

CLAUDE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Project: Tips - Transaction Inclusion Pipeline Services
2+
3+
## Notes
4+
- Always run `just ci` before claiming a task is complete and fix any issues
5+
- Use `just fix` to fix formatting and warnings
6+
- Always add dependencies to the cargo.toml in the root and reference them in the crate cargo files
7+
- Use https://crates.io/ to find dependency versions when adding new deps
8+
9+
## Project Structure
10+
```
11+
├── Cargo.toml # Workspace configuration
12+
├── ingress/ # Main binary crate
13+
├── .github/workflows/
14+
│ └── ci.yml # GitHub Actions CI
15+
```

Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[workspace]
2+
members = ["crates/ingress"]
3+
resolver = "2"
4+
5+
[workspace.dependencies]
6+
jsonrpsee = { version = "0.26", features = ["server", "macros"] }
7+
alloy-rpc-types-mev = "1.0.30"
8+
alloy-rpc-types = "1.0.30"
9+
alloy-primitives = "1.3.1"
10+
alloy-provider = "1.0.30"
11+
alloy-transport-http = "1.0.30"
12+
alloy-rpc-client = "1.0.30"
13+
tokio = { version = "1.47.1", features = ["full"] }
14+
tracing = "0.1.41"
15+
tracing-subscriber = "0.3.20"
16+
anyhow = "1.0.99"
17+
clap = { version = "4.5", features = ["derive", "env"] }
18+
url = "2.5"

crates/ingress/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "ingress"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
jsonrpsee = { workspace = true }
8+
alloy-rpc-types-mev = { workspace = true }
9+
alloy-rpc-types = { workspace = true }
10+
alloy-primitives = { workspace = true }
11+
alloy-provider = { workspace = true }
12+
alloy-transport-http = { workspace = true }
13+
alloy-rpc-client = { workspace = true }
14+
tokio = { workspace = true }
15+
tracing = { workspace = true }
16+
tracing-subscriber = { workspace = true }
17+
anyhow = { workspace = true }
18+
clap = { workspace = true }
19+
url = { workspace = true }

crates/ingress/src/main.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use alloy_provider::{ProviderBuilder, RootProvider};
2+
use clap::Parser;
3+
use jsonrpsee::server::Server;
4+
use std::net::IpAddr;
5+
use tracing::info;
6+
use url::Url;
7+
8+
mod service;
9+
use service::{IngressApiServer, IngressService};
10+
11+
#[derive(Parser, Debug)]
12+
#[command(author, version, about, long_about = None)]
13+
struct Config {
14+
/// Address to bind the RPC server to
15+
#[arg(long, env = "INGRESS_ADDRESS", default_value = "127.0.0.1")]
16+
address: IpAddr,
17+
18+
/// Port to bind the RPC server to
19+
#[arg(long, env = "INGRESS_PORT", default_value = "8080")]
20+
port: u16,
21+
22+
/// URL of the mempool service to proxy transactions to
23+
#[arg(long, env = "MEMPOOL_URL")]
24+
mempool_url: Url,
25+
}
26+
27+
#[tokio::main]
28+
async fn main() -> anyhow::Result<()> {
29+
tracing_subscriber::fmt::init();
30+
31+
let config = Config::parse();
32+
info!(
33+
message = "Starting ingress service",
34+
address = %config.address,
35+
port = config.port,
36+
mempool_url = %config.mempool_url
37+
);
38+
39+
let provider: RootProvider = ProviderBuilder::new()
40+
.disable_recommended_fillers()
41+
.connect_http(config.mempool_url);
42+
43+
let service = IngressService::new(provider);
44+
let bind_addr = format!("{}:{}", config.address, config.port);
45+
46+
let server = Server::builder().build(&bind_addr).await?;
47+
let addr = server.local_addr()?;
48+
let handle = server.start(service.into_rpc());
49+
50+
info!(
51+
message = "Ingress RPC server started",
52+
address = %addr
53+
);
54+
55+
handle.stopped().await;
56+
Ok(())
57+
}

crates/ingress/src/service.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use alloy_primitives::{B256, Bytes};
2+
use alloy_provider::{Provider, RootProvider};
3+
use alloy_rpc_types_mev::{EthBundleHash, EthCancelBundle, EthSendBundle};
4+
use jsonrpsee::{
5+
core::{RpcResult, async_trait},
6+
proc_macros::rpc,
7+
types::ErrorObjectOwned,
8+
};
9+
use tracing::warn;
10+
11+
#[rpc(server, namespace = "eth")]
12+
pub trait IngressApi {
13+
/// `eth_sendBundle` can be used to send your bundles to the builder.
14+
#[method(name = "sendBundle")]
15+
async fn send_bundle(&self, bundle: EthSendBundle) -> RpcResult<EthBundleHash>;
16+
17+
/// `eth_cancelBundle` is used to prevent a submitted bundle from being included on-chain.
18+
#[method(name = "cancelBundle")]
19+
async fn cancel_bundle(&self, request: EthCancelBundle) -> RpcResult<()>;
20+
21+
/// Handler for: `eth_sendRawTransaction`
22+
#[method(name = "sendRawTransaction")]
23+
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256>;
24+
}
25+
26+
pub struct IngressService {
27+
provider: RootProvider,
28+
}
29+
30+
impl IngressService {
31+
pub fn new(provider: RootProvider) -> Self {
32+
Self { provider }
33+
}
34+
}
35+
36+
#[async_trait]
37+
impl IngressApiServer for IngressService {
38+
async fn send_bundle(&self, _bundle: EthSendBundle) -> RpcResult<EthBundleHash> {
39+
warn!(
40+
message = "TODO: implement send_bundle",
41+
method = "send_bundle"
42+
);
43+
todo!("implement send_bundle")
44+
}
45+
46+
async fn cancel_bundle(&self, _request: EthCancelBundle) -> RpcResult<()> {
47+
warn!(
48+
message = "TODO: implement cancel_bundle",
49+
method = "cancel_bundle"
50+
);
51+
todo!("implement cancel_bundle")
52+
}
53+
54+
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256> {
55+
let response = self
56+
.provider
57+
.send_raw_transaction(tx.iter().as_slice())
58+
.await;
59+
60+
match response {
61+
Ok(r) => Ok(*r.tx_hash()),
62+
Err(e) => {
63+
warn!(
64+
message = "Failed to send raw transaction to mempool",
65+
method = "send_raw_transaction",
66+
error = %e
67+
);
68+
Err(ErrorObjectOwned::owned(
69+
-32000,
70+
format!("Failed to send transaction: {}", e),
71+
None::<()>,
72+
))
73+
}
74+
}
75+
}
76+
}

justfile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Run all CI checks locally
2+
ci: check test fmt clippy build
3+
4+
# Check code compilation
5+
check:
6+
cargo check
7+
8+
# Run tests
9+
test:
10+
cargo test
11+
12+
# Check formatting
13+
fmt:
14+
cargo fmt --all -- --check
15+
16+
# Run clippy lints
17+
clippy:
18+
cargo clippy -- -D warnings
19+
20+
# Build release binary
21+
build:
22+
cargo build
23+
24+
# Run the ingress service with default mempool URL
25+
run:
26+
cargo run -- --mempool-url http://localhost:2222
27+
28+
# Run autofixes everything
29+
fix: fmt-fix clippy-fix
30+
31+
# Format code (fix)
32+
fmt-fix:
33+
cargo fmt --all
34+
35+
# Run clippy with fixes
36+
clippy-fix:
37+
cargo clippy --fix --allow-dirty --allow-staged

0 commit comments

Comments
 (0)