Getting Started with Vortex
Point your existing Geyser client at Raiden Vortex
1. Get Access
2. Get Your Endpoint
| Region | Endpoint |
|---|---|
| FRA | http://fra.vortex.raiden.wtf:10001/ |
| AMS | http://ams.vortex.raiden.wtf:10001/ |
| NYC | http://nyc.vortex.raiden.wtf:10001/ |
| LND | http://lnd.vortex.raiden.wtf:10001/ |
Each region requires a separate subscription.
3. Authorisation
Vortex authorises by source IP. The IP you register on the dashboard is whitelisted on that region’s gateway, and connections from it are accepted without a per-request token.
Two consequences worth knowing before you connect:
- Connect from the registered IP, not through a NAT or proxy that changes it.
- One subscription is one IP. Serving several machines means either routing them through the registered address or taking a subscription per address.
You can change the registered IP from the dashboard. There is a short cooldown between changes.
4. Protocol
Vortex speaks the Geyser gRPC protocol — the same geyser.proto used by Yellowstone and Dragon’s Mouth clients. If your stack already integrates one of those, no code changes are needed.
- Service:
Geyser - RPC:
Subscribe— bidirectional streaming - Request:
SubscribeRequestwith named filter maps per method - Payload:
SubscribeUpdate, one variant per subscription method
blocks, blocks_meta and entry are not available. Vortex serves accounts, transactions and slots.
Leave the other three out of your SubscribeRequest: a client that subscribes to every method by default will need them removed.
5. Connect
Rust (yellowstone-grpc-client)
use futures::{sink::SinkExt, stream::StreamExt};
use std::collections::HashMap;
use yellowstone_grpc_client::GeyserGrpcClient;
use yellowstone_grpc_proto::prelude::{
subscribe_update::UpdateOneof, CommitmentLevel, SubscribeRequest,
SubscribeRequestFilterTransactions,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GeyserGrpcClient::build_from_shared("http://fra.vortex.raiden.wtf:10001")?
.connect()
.await?;
let mut transactions = HashMap::new();
transactions.insert(
"pumpfun".to_owned(),
SubscribeRequestFilterTransactions {
vote: Some(false),
failed: Some(false),
account_include: vec!["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P".to_owned()],
account_exclude: vec![],
account_required: vec![],
signature: None,
},
);
// blocks, blocks_meta and entry are deliberately absent: Vortex serves
// accounts, transactions and slots.
let request = SubscribeRequest {
transactions,
commitment: Some(CommitmentLevel::Processed as i32),
..Default::default()
};
let (mut sink, mut stream) = client.subscribe().await?;
sink.send(request).await?;
while let Some(message) = stream.next().await {
if let Some(UpdateOneof::Transaction(tx)) = message?.update_oneof {
println!("slot {}", tx.slot);
}
}
Ok(())
}Python (grpcio + protobuf)
Generate bindings from geyser.proto, then:
import grpc
from geyser_pb2 import SubscribeRequest, SubscribeRequestFilterTransactions
from geyser_pb2_grpc import GeyserStub
channel = grpc.insecure_channel("fra.vortex.raiden.wtf:10001")
stub = GeyserStub(channel)
def make_requests():
yield SubscribeRequest(
transactions={
"pumpfun": SubscribeRequestFilterTransactions(
vote=False,
failed=False,
account_include=["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"],
),
},
# blocks, blocks_meta and entry omitted: not served by Vortex
)
for update in stub.Subscribe(make_requests()):
if update.HasField("transaction"):
print(f"slot {update.transaction.slot}")TypeScript (@triton-one/yellowstone-grpc)
import Client, { CommitmentLevel } from '@triton-one/yellowstone-grpc';
const client = new Client('http://fra.vortex.raiden.wtf:10001', undefined, undefined);
const stream = await client.subscribe();
stream.on('data', (update) => {
if (update.transaction) {
console.log(`slot ${update.transaction.slot}`);
}
});
stream.write({
accounts: {},
slots: {},
transactions: {
pumpfun: {
vote: false,
failed: false,
accountInclude: ['6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'],
accountExclude: [],
accountRequired: [],
},
},
// blocks, blocksMeta and entry omitted: not served by Vortex
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
});6. Filtering
Each subscription method takes a map of named filters. The name is yours to choose ("pumpfun", "jupiter-swaps"), and updates arrive tagged with the filter names they matched, so one stream can serve several independent concerns.
For transactions:
| Field | Purpose |
|---|---|
account_required | Transaction must touch every listed account |
account_include | Transaction may touch any listed account |
account_exclude | Transaction must not touch any listed account |
vote | Include or exclude vote transactions |
failed | Include or exclude failed transactions |
Filtering runs server-side, so what you exclude never crosses the wire.
7. Limits
| Limit | Value |
|---|---|
| Concurrent connections | 20 |
| Named filters | 35 per connection |
| Account filters | 5,000 per named filter |
A named filter carrying more than 5,000 accounts is rejected. If you need to watch more, split them across filters, and across connections once you pass 35.
Pricing
See Pricing.
Payment in USDC on Solana via the dashboard.