mobileRumblefishLogo
Menu
  1. Software
  2. Blockchain
  3. Web3 product
  4. Smart Contracts
  5. Mobile app
  6. Web platform
  7. AWS Cloud
  8. NFT marketplace
  9. DeFi
  10. Fintech
  11. AI product
  12. dApp
  13. Crypto wallet
development tailored to your needs!

Rumble Fish helps entrepreneurs build and launch bespoke digital products.
We take care of the technology, so you can focus on your business

Join the ecosystem
of our satisfied customers:
companiesCarouselLogo0
companiesCarouselLogo1
companiesCarouselLogo2
companiesCarouselLogo3
companiesCarouselLogo4
companiesCarouselLogo0
companiesCarouselLogo1
companiesCarouselLogo2
companiesCarouselLogo3
companiesCarouselLogo4
Who we are?

Hi there! We're Rumble Fish - a team of world-class experts in bespoke software development. Our engineers are highly skilled in blockchain, cloud solutions, and defi/fintech development. Our strength and pride is the ability to take ownership of the entire development process and be a true partner and advisor for our customers. Our mission is to craft state-of-the-art digital products using battle-tested technologies. Try us!

40uniquely skilled devs
1pet-friendly office
8years in business
42projects
999passion for coding
What do we do?
Software Development Services and Skills for your needs To deliver the highest quality of services, our experts are always gaining new skills and knowledge. That’s how we make sure our solutions follow the latest industry standards and take advantage of the most innovative technologies.

Our team is well-versed and experienced in various blockchain development tools and technologies. Our unique skillset allows us to be at the forefront of Web3 development services so if you’re looking for a trusted IT partner to boost your decentralized product - look no further!

We deliver production-ready zero-knowledge proof solutions that actually ship to mainnet, specializing in custom ZK development, rollup scaling solutions, and privacy-preserving smart contracts that reduce processing times from hours to minutes. Try us!

We build fast, compliant, and cost-effective blockchain solutions on the XRP Ledger. From payment systems and tokenization platforms to enterprise DeFi applications, our team delivers production-ready systems that work when billions are on the line.

Rumble Fish builds Stellar and Soroban software for startups, enterprises, and institutions. We develop payment rails, tokenization platforms, smart contracts, and DeFi applications that draw on Stellar's speed, low costs, and financial infrastructure.

We build smart contracts that handle real business complexity without the usual blockchain headaches. From DeFi protocols to custom on-chain systems, we deliver production-ready solutions that scale.

Decentralized Finance (DeFi) development requires an extensive amount of blockchain knowledge, as well as a great understanding of financial mechanisms. We’ve got both that bases covered! Our team has successfully built an impressive number of DeFi products like cryptocurrency exchanges, dApps, lending protocols, or staking platforms. Try us!

Our experienced team will take your AWS cloud solutions to the next level. AWS provides purpose-built tools to support your needs, and it is the preferred choice for any blockchain project. From the plethora of cloud tools and solutions offered by Amazon Web Services, we’ll help you choose and implement the ones that serve your business the best way possible.

AI chatbots can bring value to a wide range of industries by enhancing customer interactions, streamlining processes, and improving overall efficiency. We'll craft a perfect AI assistant for your product.

Need realistic data for AI training, testing, or product development—but privacy, scale, or availability is blocking you? We engineer custom synthetic data solutions that capture the complexity of real-world data without the constraints. From multi-modal generation to domain-specific datasets, we build what platforms can't deliver.

We build custom AI knowledge management systems that turn your scattered enterprise knowledge into instant, accurate answers - no more employees wasting their valuable time hunting through SharePoint and Slack for information. Unlike platforms that trap you in subscriptions, we engineer RAG solutions specifically for your data and security requirements, then hand you complete ownership of the source code and infrastructure.

Looking for a skilled team to help you build an advanced fintech platform able to compete with the biggest in the game? At Rumble Fish, we’ve got what it takes to engineer innovative financial technology systems. We offer end-to-end fintech software development, consulting, and expertise.

Our experts provide you with knowledge, skills, and experience that elevates every project to another level. We’ll gladly take ownership of the entire process and guide you and your team through the intricacies of cutting-edge technology development.

If you’re in need of professional web development services, look no further! Rumble Fish's talented team has extensive experience in delivering top-tier web apps and websites with the use of battle-tested tools and technologies like React or Nest. We know just the right solutions to exceed your business requirements.

Whether you need an Android, an IOS app, or both, the Rumble Fish team is here to help you deliver the beautiful and efficient mobile product that your customers will simply love to use! We craft fast and secure mobile apps with a wow factor to help our customers grow their businesses and reach their goals quicker.

If you're looking for a team capable of turning your product concept into a beautiful and technologically intricate digital solution - look no further! Rumble Fish is your trusted software development partner ready to take you through the entire process of custom digital product creation - from the early stages of ideation to the post-launch support. Whether you're on a mission to build a mobile app, a Web3 product, or an advanced platform - we are here for you!

We design sleek, intuitive, and highly effective interfaces to help you overcome your business challenges. After carefully evaluating and understanding your requirements we switch to the designing mode - the end goal is the beautiful digital solution that people love to use!
Testimonials
See what our customers say about working with us
Latest case studyPorting Merkl to Stellar: Full Protocol Migration to Soroban
Porting Merkl to Stellar: Full Protocol Migration to Soroban
Merkl is the leading onchain incentive infrastructure, having distributed over $1.6B in rewards for 250+ companies across 60+ chains.
Collaboration timeframe:4 weeks
Services:Smart Contract Development, Blockchain Development, Stellar Product Development, DeFi Development
We're trusted by global innovators and leaders.Join them!
TURNTABLE
A hybrid of a social network and a music app
TURNTABLE
MAKERDAO
The first truly decentralized stablecoin crypto on Ethereum
MAKERDAO
ZBAY
A private inbox, wallet, and marketplace all in one
ZBAY
VERIFYID
An identity verification MVP
VERIFYID
Rumblefish Blog
Check a piece of expert knowledge
Stellar vs Ethereum: Choosing the Right Blockchain for Payment Infrastructure_BlogPostImageStellar vs Ethereum: Choosing the Right Blockchain for Payment Infrastructure
Ethereum and Stellar are both enormous networks with real production deployments in payments. However, they were designed around different assumptions about what "payment" means, and those assumptions surface everywhere once you start building. This is a practical comparison based on what it actually takes to ship a payment product on each. Let's dive in! ### What Each Network Was Designed For Ethereum launched in 2015 as a general-purpose programmable blockchain. Payments are possible on Ethereum, but they were never the primary design goal. The network was built to support arbitrary computation, and payments are one application among many. That design philosophy has consequences that run through the entire stack. Stellar launched in 2014 with a narrower mandate: fast, cheap, cross-border value transfer. The native asset model, the built-in order book, the Stellar Consensus Protocol - all of it reflects the assumption that the primary use case is moving money between parties, including parties on different rails and in different currencies. Soroban, Stellar's smart contract platform, arrived later and extended that foundation without replacing it. This distinction shapes what you get for free and what you have to build yourself. On Ethereum, you're adapting a general-purpose machine to payments. On Stellar, payments are the default path, and you extend from there. ### Transaction Costs and Finality The fee difference between Ethereum mainnet and Stellar is not marginal. A simple ETH transfer on mainnet costs somewhere between $0.50 and $5 depending on network conditions, and during congestion it has gone above $50. An ERC-20 transfer costs more than a native transfer because it executes contract code. For any payment product where volume is high or average transaction size is modest, Ethereum mainnet fees are a structural problem, not an occasional inconvenience. Stellar's base fee is 100 stroops, or 0.00001 XLM. At current prices, that's a fraction of a cent. The network uses fee bumping for prioritization rather than a gas auction, so costs are predictable rather than volatile. For a product processing thousands of transactions per day, the fee difference between the two networks compounds into a real infrastructure cost advantage for Stellar. Finality follows a similar pattern. Ethereum achieves probabilistic finality: a transaction is considered settled after enough blocks have been added on top of it, which in practice means waiting several minutes for high-confidence confirmation. Stellar's consensus protocol achieves deterministic finality in 3 to 5 seconds. A transaction either made it into a closed ledger or it didn't. There is no "probably settled" state to manage. For payment applications with compliance requirements around settlement timing, that distinction simplifies a significant amount of downstream logic. Layer 2 networks on Ethereum (Arbitrum, Optimism, Base) close the fee gap considerably. Fees on L2s are typically under a cent, and finality on the L2 itself is fast. But L2 finality and Ethereum mainnet finality are different things, and products with strict settlement requirements need to think carefully about which one they actually need. The L2 ecosystem also adds operational complexity: bridge risk, liquidity fragmentation across chains, and a developer environment that varies between rollups. ### The Asset Model and What It Saves You One of Stellar's less-discussed advantages for blockchain payment infrastructure is its native asset model. Any account on Stellar can issue an asset, a stablecoin, tokenized fiat, a loyalty instrument, and those assets are first-class citizens on the network. The built-in decentralized exchange means that paths between assets exist automatically: a sender can pay in one currency and a recipient can receive in another, with conversion handled inside the transaction itself. This is not a DeFi protocol layered on top of the base layer; it is the base layer. On Ethereum, building equivalent functionality requires smart contracts. A stablecoin is an ERC-20 contract. A swap between two stablecoins goes through a DEX or custom contract logic. Each additional layer adds gas cost, audit surface, and failure modes. For complex payment routing across currencies, the contract code required on Ethereum is substantially more involved than the equivalent path payment on Stellar. Soroban extends this further. With Soroban smart contracts, you can add programmable payment logic - conditional releases, escrow, multi-party settlement - directly on top of Stellar's native asset model. A Soroban contract interacts with native Stellar assets without replacing them. You get programmability and the built-in payment primitives, which is a different architecture from Ethereum, where the asset model and the execution environment are the same thing. ### Compliance and Institutional Considerations Payment products in regulated environments have requirements beyond raw technical performance. KYC, AML, transaction monitoring, the ability to freeze assets in response to legal orders: these are table stakes for anything handling real money in most jurisdictions. Stellar has compliance controls at the protocol level. Regulated assets can require authorization before an account can hold or transact them. An issuer can freeze a specific account's holdings or globally freeze an asset. These controls are part of the asset model, not implemented via contract code. For an institution that needs to demonstrate asset control to regulators or auditors, the fact that these are protocol primitives rather than custom contract logic reduces implementation risk and simplifies the audit. Ethereum supports equivalent functionality through smart contract design. A well-written ERC-20 can include pause functions, blocklists, and administrative controls. The difference is that on Ethereum, you're implementing and auditing those controls yourself, while on Stellar, they're part of the protocol specification. The failure mode on Ethereum is a smart contract bug. The failure mode on Stellar is a misconfigured flag. Both are manageable, but they require different expertise and carry different audit costs. ### Where Ethereum Has the Advantage This is not a case where one network is better for all payment use cases. * The Ethereum developer ecosystem is larger by an order of magnitude. Tooling is more mature, auditing firms have deeper Ethereum experience, and the pool of engineers who can be hired is bigger. For a team building from scratch without existing blockchain expertise, Ethereum has a shorter path to production. * DeFi liquidity lives predominantly on Ethereum and its L2s. If your payment product needs to interact with lending markets, AMMs, or yield protocols, the depth of what's available on Arbitrum or Optimism is not matched on Stellar. Soroban-based DeFi is growing, but it's early. For blockchains for DeFi with complex composability requirements, Ethereum remains the stronger environment. * Token distribution also favors Ethereum. USDC and USDT have large liquidity pools on Ethereum. If your users already hold stablecoins there, moving them to a Stellar-based product requires a bridging step that adds friction. For consumer-facing products where users arrive with existing balances, that friction is real. ### How to Make the Call The right choice depends on what your payment product actually does, and a few questions tend to clarify it quickly. **What's the expected transaction volume and average transaction size?**  * High volume, small transactions: Stellar's fee model is a structural cost advantage that compounds at scale. * Low volume, large transactions: Ethereum mainnet fees are manageable, and the ecosystem benefits may outweigh them. **Do you need programmable logic beyond basic transfers?**  * Soroban handles most payment-adjacent use cases now. If your logic requires deep integration with Ethereum DeFi protocols, that tips the balance toward Ethereum L2. **Do you have regulatory requirements around asset control?**  * Stellar's protocol-level compliance features reduce implementation risk in ways that matter to compliance teams and reduce audit scope. **Where do your users and liquidity already live?**  * Building a new corridor from scratch: Stellar is a strong default. Plugging into an existing Ethereum-native ecosystem: the switching cost probably doesn't justify the move. At Rumble Fish, the payment projects that have gone smoothest on Stellar share a common profile: high transaction volumes, multi-currency requirements, and institutional compliance needs. Projects where Ethereum made more sense were those where DeFi composability was central, or where the team was already deep in the Ethereum stack and rebuilding on a new network would have cost more than it saved. For most payment applications, the comparison between Ethereum and Stellar is not about which network is technically superior in the abstract. It's about which one matches the shape of your problem. If you're working through that decision and want a second opinion from a team that has made it in production, [we're happy to talk](https://www.rumblefish.dev/contact/).
Blockchain
Serverless at the Edge of a Blockchain: Architecture Decisions Behind Our Soroban Explorer_BlogPostImageServerless at the Edge of a Blockchain: Architecture Decisions Behind Our Soroban Explorer
Marek-Kowalski.png_BlogPostAuthorAvatarBy Marek Kowalski
Earlier this year, Rumble Fish received a $131,200 grant from the Stellar Community Fund to build a Soroban-first block explorer,  a publicly accessible tool for navigating transactions, smart contracts, accounts, and events on the Stellar network. The grant comes with a public mandate: the repository is open source, the infrastructure is reproducible, and the whole thing has to work reliably at mainnet scale. Block explorers sound like a solved problem. They are not, at least not for Soroban. Soroban is Stellar's smart contract platform, and it produces data structures that existing explorers don't fully surface: decoded contract invocation arguments, return values, nested call trees, and CAP-67 contract events. Beyond that, the Stellar protocol produces a new binary payload, a \`LedgerCloseMeta\` XDR file, every five to six seconds, containing the complete record of every change that occurred in that ledger close. You need to ingest it in near-real time, decode it, store it, and serve it through a public API before the next one arrives. This article walks through the decisions that shaped our architecture. Some of them are conventional. A few are not. We replaced a planned 7 TB PostgreSQL database with a 900 MB ClickHouse instance. We run our backend Lambdas in Rust. We ran the historical backfill on local machines because that was the right tool for that specific job. Here is how we got there. ## Why We Don't Call Any External API The straightforward approach to building a block explorer is wrapping an existing one. Horizon has been the standard Stellar API for years. Soroban RPC provides contract-level access. Both were options, and we rejected both of them. **Horizon is deprecated** for the indexing use cases we need. The Stellar Foundation's own tooling has moved beyond it, and building on a deprecated API means inheriting its limitations permanently. **Rate limits are fine until they're not.** A block explorer that depends on another service's API inherits that service's reliability ceiling. Traffic spikes on the Stellar network, exactly when users want a block explorer most, are also when upstream APIs are most likely to throttle requests. **Soroban-specific data isn't pre-assembled anywhere.** We need decoded contract invocation trees showing nested contract-to-contract calls. We need function arguments and return values decoded from their binary \`ScVal\` representation into structured, readable data. We need function signatures extracted from the WASM bytecode at contract deployment time. None of this exists in a form we can simply fetch from an existing API. The decision to own the pipeline end-to-end was made early in the process and has not been reconsidered since. Every other architectural choice in this article follows from it. If we had accepted an external API dependency, most of what follows wouldn't have been necessary. ## **One Monorepo, Multiple Languages - The Nx Choice** The project has eight distinct packages spanning TypeScript and Rust:   | Package | Language | Role | | --- | --- | --- | | \`apps/indexer\` | Rust | Ledger Processor Lambda - XDR ingestion | | \`apps/workers\` | Rust | Event Interpreter Lambda - enrichment | | \`apps/api\` | Rust | REST API Lambda | | \`apps/web\` | TypeScript | React SPA | | \`infra/aws-cdk\` | TypeScript | CDK infrastructure | | \`libs/domain\` | TypeScript | Shared explorer types | | \`libs/shared\` | TypeScript | Generic utilities | | \`libs/ui\` | TypeScript | Reusable React components | These are not independent microservices that happen to live in the same repository, but they are genuinely coupled. The domain types the frontend uses to render a transaction are the same concepts the indexer writes to the database. A change to how we store Soroban invocations touches both the Ledger Processor and the API. The CDK stack deploys all three Lambdas and knows their artifact paths. The coupling is real; the only question is whether to make it visible or hide it across repository boundaries. We chose [Nx](https://nx.dev) to make it visible. With Nx, \`nx affected --target=build\` builds only the packages touched by a given change. On a workspace with eight packages across two languages, this matters: a change to \`libs/ui\` should not trigger a Rust compilation. \`nx run-many -t typecheck\` runs TypeScript type checking across all TypeScript packages in one command. The project dependency graph is explicit and visualisable - you can see at a glance that \`apps/api\` depends on \`libs/domain\`, and that \`infra/aws-cdk\` depends on nothing in the application layer but deploys everything. The alternative (one repository per service) would have distributed the coupling across network boundaries rather than eliminated it. You would end up with shared type packages, inter-repo version pinning, and deployment coordination scripts that reinvent what a monorepo gives you for free. We have seen that pattern enough times to prefer the explicit version. ## Why We Write Our Lambdas in Rust Rumble Fish has historically written backends in TypeScript. It is ergonomic, the ecosystem is extensive, and getting a new engineer productive in a Node.js Lambda takes hours, not weeks. For this project, we made a different choice: all three backend Lambda functions are Rust crates. Here is why. ### Cold start performance Lambda cold starts are a function of two things: how large the deployment artifact is and how expensive the runtime initialisation is. A TypeScript Lambda ships a Node.js runtime plus your application code plus its \`node\_modules\` - commonly several megabytes, sometimes significantly more. A compiled Rust Lambda is a single statically-linked binary, typically under five megabytes, with no runtime to initialise. It starts in milliseconds. For the Ledger Processor, which fires on every S3 event - roughly 17,000 times a day - provisioned concurrency is not a practical solution. Provisioned concurrency keeps instances warm, but it makes most sense for steady-state traffic, not for a function that needs to respond to an event every five seconds indefinitely. A fast cold start is preferable to paying for warmth. ### Execution speed XDR parsing is not lightweight. Each \`LedgerCloseMeta\` payload contains every transaction, every operation, every Soroban invocation, every CAP-67 event, and every ledger entry change for a complete ledger close. For an active ledger, that can mean thousands of decode operations: binary deserialisation, tree traversal, type-tagged value decoding. Rust does this with predictable memory usage, no garbage collection pauses, and throughput that is roughly an order of magnitude higher than equivalent Node.js. Our target is under ten seconds from ledger close to database write. With the Ledger Processor in Rust, we are well inside it with headroom. ### The AI development loop This is the argument we did not expect to be making when the project started. The Rust compiler is famously strict. Ownership violations, type mismatches, and lifetime errors all surface at compile time with precise, often instructive messages. This turns out to be highly productive when working with AI-assisted development: the agent writes code, the compiler rejects it with a specific error, the agent reads the error, and corrects it. The loop is fast and deterministic. There is no class of "it ran but produced the wrong output" error that requires runtime investigation. With TypeScript or Python, AI-generated code can be syntactically valid and dynamically typed in ways that fail silently at runtime or produce subtly wrong results. With Rust, the compiler acts as a continuous integration step on every compilation. Errors are loud, early, and actionable. As AI tooling has made Rust more accessible, removing much of the manual borrow-checker wrestling that historically made it a steep climb, the performance and correctness benefits have become easier to capture. We now consider it the better default for backend Lambda work, and this project is the system that shifted our thinking. AWS supports Rust as a first-class Lambda runtime. The \`lambda\_runtime\` crate, \`aws-sdk-rust\`, and the \`cargo-lambda\` build toolchain cover everything needed from local development to deployment. ## The Ingestion Pipeline: Matching Compute to Workload Shape The ingestion pipeline has three distinct jobs. We use three different execution models for them, because the workloads have different shapes, and applying one model to all three would have been a mistake. ```plaintext Stellar peers → Galexie (ECS Fargate, continuous) → S3: stellar-ledger-data/ (~1 file per ledger, zstd-compressed XDR) → Ledger Processor Lambda (Rust, S3 PutObject trigger) → ClickHouse (Hetzner) ↑ Event Interpreter Lambda (Rust, EventBridge every 5 min) API Gateway → API Lambda (Rust) → ClickHouse (Hetzner) CloudFront → React SPA ``` ### Galexie on ECS Fargate Galexie is the Stellar Foundation's tool for streaming canonical ledger data. It connects to Stellar network peers via an embedded Captive Core process, maintains a persistent connection, and exports one \`LedgerCloseMeta\` XDR file to S3 for each ledger close - roughly every five to six seconds, indefinitely. Lambda is the wrong shape for this. Galexie is a long-running, stateful process. It maintains a peer connection across ledger closes, tracks which ledger it last exported, and resumes from that checkpoint on restart. Lambda has a fifteen-minute execution limit and no concept of resumption. ECS Fargate gives us a managed container runtime - one task, always running, no EC2 to provision or patch. ### Lambda (Rust) for the Ledger Processor When Galexie writes a file to S3, an S3 PutObject notification triggers the Ledger Processor Lambda. This is the primary ingestion worker, and it is exactly the shape that Lambda is designed for: one event, one bounded unit of work, invoked per ledger close, completing in well under ten seconds. The Lambda downloads and decompresses the XDR file, parses every entity it contains, and writes structured records to ClickHouse in a single operation. If the Lambda fails, Lambda retries automatically. If there is a permanent failure, the file remains in S3 and we can replay any ledger by re-triggering the Lambda with its S3 key. That replayability is the reason S3 is the handoff between Galexie and the Ledger Processor, rather than a direct invocation or a queue. A durable artifact per ledger close means the ingestion pipeline can recover from failures, schema migrations, or bugs in the parsing logic by replaying affected ledgers without re-ingesting from the network. ### Lambda (Rust) for the Event Interpreter A third Lambda fires every five minutes via EventBridge. It reads recently stored Soroban events and pattern-matches against known DeFi protocols - Soroswap, Aquarius, Phoenix - to generate human-readable summaries: "Swapped 100 USDC for 95.2 XLM." This lives in a separate Lambda from the Ledger Processor deliberately. Our interpretation heuristics improve over time as we recognise new protocols and refine existing patterns. Keeping enrichment separate from ingestion means we can update interpretation logic, redeploy the Event Interpreter, and re-run it over historical events, all without touching the ingestion path. ## The Historical Backfill: When Architecture Meets Reality Soroban launched on the Stellar mainnet in late 2023. Our explorer needs to surface data from the beginning, which means indexing roughly two years of history before going live. The design called for a separate ECS Fargate task to read from Stellar's public history archives and feed data through the same S3 → Lambda → ClickHouse pipeline as live ingestion; one code path for both problems, clean separation, no special cases. We did not do that. Instead, we ran the backfill on local machines, writing directly to a local ClickHouse instance. Once the backfill was complete, we migrated the data to production ClickHouse on Hetzner.  There were two reasons for that approach: speed and cost. The event-driven pipeline is optimised for steady, continuous work - one ledger at a time, one S3 event at a time, with the overhead of Lambda invocations, S3 round-trips, and network hops to the database. That overhead is trivially small for live ingestion, where a new ledger arrives every five seconds. For a one-time bulk operation across millions of historical ledgers, the same overhead becomes the bottleneck. A local machine writing directly to a local database processes historical data at a rate that the serverless pipeline cannot match. Cost follows the same logic. Lambda invocations, S3 data transfer, and remote database writes during a multi-week bulk ingest all accumulate. Running on hardware you already own costs nothing beyond electricity. The lesson is straightforward: the event-driven architecture is the right shape for what it was designed for - continuous, low-latency, per-ledger ingestion. It is not the right shape for a one-time bulk operation. Treating the backfill as its own case is the architecture working as intended. ## ClickHouse on Hetzner: Why We Left AWS for the Database When we designed the database schema in PostgreSQL and tested it against a batch of ledgers, the extrapolated storage size for the full Stellar history came to approximately 7 TB. The same data in ClickHouse takes roughly 900 MB. ClickHouse is a columnar database. Instead of storing rows, all fields for a given record are adjacent in storage, it stores columns, all values for a given field adjacent. For blockchain data, this is a significant advantage. Account IDs, contract addresses, operation types, ledger sequences, and status codes repeat millions of times across the dataset. Column-adjacent storage lets the compression algorithm - LZ4 or ZSTD per column - exploit that repetition far more aggressively than a row-oriented layout allows. The result is storage that is not marginally smaller but categorically smaller: a dataset you would otherwise manage in terabytes fits comfortably in gigabytes. Beyond compression, ClickHouse's columnar layout is naturally suited to the queries a block explorer serves. Every page is some form of time-range scan: recent transactions, recent invocations of a contract, event history for a ledger sequence range. Columnar databases read only the columns a query touches, which, for range scans over a subset of fields, is substantially less I/O than a row store that reads entire rows. **Why not DynamoDB?** DynamoDB is optimised for single-row lookups at a very large scale. A block explorer's queries, all invocations of contract X ordered by ledger, all transactions from account Y in the last thirty days, aggregate event counts by type, are not single-row lookups. Modelling them efficiently in DynamoDB would require denormalising every read pattern at write time. With a query surface as wide as ours, that is an ongoing maintenance burden every time the frontend adds a new page. **Why Hetzner?** ClickHouse is not available as a managed service on AWS. Running it on Hetzner gives us a dedicated server with NVMe storage at a fraction of the cost of an equivalent managed database instance. Hetzner's pricing is particularly favourable for storage-heavy analytical workloads. This makes our architecture hybrid: compute on AWS (Lambda, ECS Fargate, API Gateway, CloudFront) and database on Hetzner. The Lambda runtime does not care which cloud the database lives in. The connection is a standard TCP connection to a ClickHouse HTTP interface, the same way any other client would connect. Keeping everything under one vendor's roof is a convenience, not a technical requirement, and in this case, it was a convenience we traded for a 7 TB reduction in storage. ## CDK in TypeScript: Infrastructure in the Monorepo All infrastructure is defined in AWS CDK using TypeScript, in \`infra/aws-cdk\` inside the same Nx monorepo as the application code. The concrete benefit is that the same language, the same toolchain, and the same compiler that validates the application also validates the infrastructure. Environment names are typed constants shared across CDK and application code. S3 bucket key formats are defined once. A misconfigured Lambda environment variable that references a non-existent secret name fails at \`cdk synth\` rather than at runtime. One choice worth being explicit about: GitHub Actions authenticates to AWS using OIDC rather than long-lived credentials. The Actions workflow assumes a scoped IAM role at deploy time; no AWS keys are stored in GitHub secrets. For a public repository, this is not optional - any credential committed to a public repo is compromised immediately. OIDC eliminates the credential management problem at its source. The CDK stack is fully reproducible. The design intention from the beginning was that anyone - including the Stellar Foundation or any other team in the ecosystem - should be able to clone the repository and \`cdk deploy\` a complete working copy of the system in a fresh AWS account. The architecture is public infrastructure, not proprietary tooling. ## What We Would Do the Same Way Again The Soroban block explorer is past Milestone 1 - historical backfill complete, live ingestion running, indexing the Stellar mainnet in real time and looking back at the architectural choices, a few stand out as clearly right. **Owning the pipeline.** The decision to ingest directly from the canonical ledger rather than wrapping an external API has paid for itself many times over. We control what data we store, how we store it, and how we serve it. There is no upstream reliability dependency, no rate limit, and no undocumented behaviour we cannot inspect. **Rust for Lambdas.** The cold start performance is real, the XDR parsing throughput is real, and the AI development loop has been a genuine productivity multiplier. We would make the same choice again, and we expect to make it on future projects. **Nx for the hybrid monorepo.** Coupling between frontend, backend, infrastructure, and shared libraries is not something you can wish away by splitting into multiple repositories. Making it explicit, making it visible, and tooling around it has made the codebase easier to navigate and the CI pipeline faster to run. **ClickHouse on Hetzner.** Seven terabytes versus nine hundred megabytes is not a marginal improvement. It is a different order of infrastructure, and once we saw that number, we did not seriously consider the alternative. **The pragmatic backfill.** Running history on local machines and migrating the result was the right call. The elegant solution and the correct solution are not always the same. --- The repository is [public on GitHub.](https://github.com/rumblefishdev/soroban-block-explorer)  The grant announcement with more background on the project is [on our blog.](https://www.rumblefish.dev/blog/post/rumble-fish-grant-stellar-block-explorer/) If you are building something with a similar shape - event-driven ingestion, analytical storage, serverless compute - we are happy [to talk through it.](https://rumblefish.dev/contact)
Blockchain
Have an idea?
Let’s work
together!
We will answer any questions you may have related to your startup journey!Do you prefer e-mail?
hello@rumblefish.pl