McLeod Bob-Manuel
All writing

Owning a feature that moved $14M in its first two months

Product ownership lessons from building cross-chain stablecoin settlement: defining done as money arriving, making every state explicit, and removing manual recovery.

Sotonye McLeod Bob-Manuel4 min read

In part one I wrote about scaling a wallet platform. This post is about one feature on top of it, and about the difference between building something and owning it.

The feature was cross-chain stablecoin settlement. A customer holds USDC on one network and needs to pay someone on another, or holds USDT and needs to deliver EURC. Before, that meant a manual bridge, a swap, a wait, and a nervous look at a block explorer. After, it was one request. In its first two months it processed more than $14M, with a median settlement time of about 27 seconds from request to funds arriving.

None of the individual pieces were new. What made it work was a set of decisions about what “done” means.

Own the problem, not the ticket

The narrow version of this feature is easy to describe: support payouts from one chain to another. You could build exactly that, close the ticket, and it would work in the demo.

But the customer’s problem wasn’t “move tokens between chains”. It was “my counterparty gets paid, in the asset they want, and I can prove it”. That framing changes what you build. It means handling the asset conversion, not only the transfer. It means telling the customer what is happening at each step, and it means caring about the failure cases as much as the happy path, because the failure cases are the ones people remember.

Most of the work that mattered was outside the ticket.

Define done as “the money arrived”

We measured one thing above everything else: time from request to funds landing in the recipient’s wallet, end to end. Not API latency. Not how fast we broadcast a transaction. Arrival.

That single metric kept the team honest. A transfer that is “submitted” but stuck on a bridge for twenty minutes looks fine on most dashboards. It doesn’t look fine to the person waiting for it. Measuring arrival meant every slow step showed up, including the ones that weren’t our code.

Make every state explicit

Cross-chain payouts have a lot of ways to go wrong in the middle. A bridge can stall. A network can congest. A request can be retried by a nervous client while the first one is still in flight.

A payout moves through requested, reserved, submitted, confirmed and settled; a self-healing worker picks up anything stuck and either retries it with the same key or resumes it where it stopped.
A payout can only move forward or be put right. It can never skip a step or happen twice.

So every payout lives in an explicit state, and it can only move forward. Funds are reserved in the same step that accepts the request, so two requests can never spend the same balance. The customer’s idempotency key follows the payout through every retry, including retries of the bridge, so sending the same request twice returns the first result instead of paying twice.

When something does get stuck, a background worker notices that a payout has been in a state longer than it should be. Because the state is recorded, the worker knows whether to retry, resume from the last confirmed step, or release the funds and tell the customer. Nobody has to open a spreadsheet and work out what happened.

Speed comes from removing manual recovery

People sometimes assume a 27-second median comes from a fast chain or a clever route. Some of it does. Most of it comes from never waiting for a human.

In a lot of payment systems, the slow part isn’t the transfer. It’s the transfer that went wrong, sat in a queue until someone noticed, and then waited for someone to investigate. Take that out and the median drops, but more importantly the tail drops, and the tail is what customers complain about.

Ship the docs with the feature

We treated the documentation, examples and SDK support as part of the feature, not a follow-up task. For a B2B product, the integration is the product. If a developer can’t get a test payout working in an afternoon, it doesn’t matter how good the settlement engine is.

What ownership actually means

Looking back, owning this feature meant three things I’d now expect from anyone leading a product.

You decide what done means, and you define it from the customer’s side, not the code’s. You stay accountable after launch, when the interesting work is over and the operational work begins. And you treat the failure paths as the product, because in payments, they are.

It’s also the part of the job I enjoy most. Writing code that works is satisfying. Watching $14M move through something you designed, with almost nobody needing to think about it, is better.

  • Product engineering
  • Ownership
  • Payments
  • Reliability