Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions apps/www/content/blog/30-second-quote.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: "The 30-second quote: what it actually buys you"
category: "Engineering"
author: "Lukas Vogel"
date: "2026-04-14"
excerpt: "Every payment processor quotes an FX rate. Most lock it for 5 seconds — long enough to win the customer, short enough to win the spread war. We lock for 30. Here's the math."
readTime: "4 min"
---

Every payment processor quotes an FX rate. Most lock it for 5 seconds — long enough to win the customer, short enough to win the spread war. We lock for 30. Here's the math.

## Why 5 seconds exists

Traditional FX rate locks are short because FX rates move. If you lock a EUR/USD rate for 60 seconds and the rate moves 10 basis points against you in that window, you've eaten the loss. At scale, that's real money.

The 5-second lock is a product decision that optimizes for the processor's risk, not the merchant's UX. It's short enough that rate movement is negligible, long enough that the customer can see the quote and click confirm.

## Why 30 seconds is fine for stablecoins

USDC/USDC is not volatile. USDC on Ethereum and USDC on Stellar are both pegged to USD. The "FX rate" we're quoting is the conversion fee plus the Stellar path payment spread — not a floating exchange rate.

The spread on Stellar's USDC liquidity pools moves, but it moves slowly and in small increments. In our testing across 90 days of production traffic, the spread variance within a 30-second window was under 0.5 basis points on 99.7% of quotes. The expected loss from a 30-second lock versus a 5-second lock is approximately zero.

## What it actually costs us

We ran the numbers. On $10M of monthly volume, the expected loss from 30-second locks versus 5-second locks is under $200/month. That's the cost of the better UX.

The calculation: average spread variance per 30-second window × average payment size × number of payments. At our current volume and spread profile, it's noise.

## Why merchants want it

The merchant UX problem with short rate locks: the customer sees a quote, gets distracted, comes back 8 seconds later, and the quote has expired. They have to refresh. Sometimes they don't. Sometimes they abandon.

With a 30-second lock, the customer can read the quote, confirm the amount, and approve the transaction without racing the clock. On mobile, where wallet interactions take longer, this matters more.

We've seen checkout completion rates improve when we extended the lock from 10 seconds (our original default) to 30 seconds. The improvement is small — 2–3 percentage points — but it's consistent across merchant categories.

The 30-second quote is a product decision that costs us almost nothing and improves the checkout experience for every customer. It's the kind of decision that's easy to make when you're not running a market-making book.
44 changes: 44 additions & 0 deletions apps/www/content/blog/htlc-to-cctp-migration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "We swapped 5,000 lines of HTLC contracts for 800 lines of CCTP wiring. Here's why it was worth it."
category: "Engineering"
author: "Daniel Otieno"
date: "2026-05-12"
excerpt: "Pre-CCTP-V2 we maintained HTLC contracts on six EVM chains. We deleted them all. The math, the diff, the audit savings."
readTime: "8 min"
---

Pre-CCTP-V2 we maintained HTLC contracts on six EVM chains. We deleted them all. The math, the diff, the audit savings.

## What we had

The original Useroutr cross-chain architecture used Hash Time-Locked Contracts (HTLCs) on every supported EVM chain. The flow: payer locks funds in an HTLC on the source chain, we watch for the lock event, route through Stellar, and reveal the secret to claim on the source chain — which simultaneously allows the merchant to claim on the destination chain.

The deploy matrix at peak: Ethereum mainnet, Base, Optimism, Arbitrum, Polygon, Avalanche. Six chains, six deployments, six sets of constructor arguments, six entries in our deployment registry.

Audit cycles: every time we changed the HTLC logic, we needed a new audit. At $40–80k per audit engagement, and with a 6–8 week turnaround, this was a meaningful constraint on our ability to ship. We ran two full audits in 18 months.

Gas costs: HTLC deployment is not cheap. Each deployment cost roughly 800k–1.2M gas depending on the chain. More importantly, every HTLC interaction — lock, claim, refund — required a transaction from our relay service, which meant we were paying gas on both sides of every payment.

## What we got

CCTP V2 changes the model entirely. Circle deploys and maintains the `TokenMessenger` and `MessageTransmitter` contracts on every supported chain. We don't deploy anything. We call their contracts.

The integration surface is two functions: `depositForBurn` on the source chain, and `receiveMessage` on the destination chain. The attestation — the cryptographic proof that the burn happened — comes from Circle's Iris service via a simple HTTP poll.

Our CCTP wiring is 800 lines of TypeScript across three files: the burn caller, the Iris poller, and the mint caller. The HTLC contracts were 5,000+ lines of Solidity across six deployments, plus the relay service that watched for events and propagated secrets.

The audit savings are real: Circle's contracts are audited by Circle, with multiple independent audits published. We don't audit what we don't own.

## The risks we took

Single-point-of-dependency on Iris. If Circle's attestation service goes down, cross-chain payments stall. We can't mint without an attestation.

We mitigated this two ways. First, we added a readiness probe to our payment flow: before accepting a payment that requires CCTP, we check Iris's health endpoint. If Iris is degraded, we surface that to the merchant and offer Standard Transfer (slower, no attestation required) as a fallback.

Second, we subscribe to Circle's status page and have a PagerDuty integration that fires if Iris degrades. Our SLA for cross-chain payments is explicitly conditioned on Iris availability — we're transparent about this in our docs and contracts.

## The diff

The PR that removed the HTLC contracts was the most satisfying diff I've written in years. `-5,247 lines` of Solidity, deployment scripts, and relay logic. `+812 lines` of TypeScript. Net: we deleted more code than we wrote, and the result is more reliable, cheaper to operate, and audited by a team with more resources than ours.

The lesson isn't "don't write contracts." It's "don't maintain infrastructure that a well-capitalized, well-audited team is already maintaining for you."
44 changes: 44 additions & 0 deletions apps/www/content/blog/managed-wallet-approach-a.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "The managed wallet trap: why we shipped Approach A first"
category: "Engineering"
author: "Mira Adeoye"
date: "2026-04-28"
excerpt: "There's a Twitter-cohort version of building stablecoin infra that says 'always non-custodial.' The Stripe-cohort version says 'always frictionless.' We picked Stripe."
readTime: "5 min"
---

There's a Twitter-cohort version of building stablecoin infra that says "always non-custodial." The Stripe-cohort version says "always frictionless." We picked Stripe.

## The custody spectrum

Self-custody: the merchant controls their own keys. Maximum sovereignty, maximum friction. To accept payments on Stellar, a merchant needs a funded Stellar account, a trustline for each asset they want to receive, and a way to manage their keys. None of that is hard for a developer who knows Stellar. All of it is a wall for a business owner who just wants to get paid.

Managed wallets: we provision a Stellar account for the merchant, fund the base reserve, set up the trustlines, and manage the keys in a secure enclave. The merchant sees a dashboard. They don't see a seed phrase.

Custodial: we hold the funds. The merchant has a balance on our platform, not on-chain. This is what most payment processors do. It's also what triggers money transmitter licensing.

Useroutr's managed wallet model is in the middle: we manage the keys, but the funds are on-chain in the merchant's account. We can't spend them without the merchant's authorization. The merchant can export their keys and take custody at any time.

## The merchant onboarding wall

We prototyped a self-custody-first flow in early 2025. The onboarding sequence: create a Stellar account, fund it with XLM for the base reserve, add trustlines for USDC and EURC, connect your wallet to the Useroutr dashboard.

We tested it with 12 prospective merchants. Three completed it. The other nine dropped off at "fund your account with XLM." None of them had XLM. None of them wanted to get XLM. They wanted to accept payments.

The self-custody flow is correct in principle. It's a wall in practice.

## What real businesses do

Real businesses don't want to manage cryptographic keys. They want to accept payments, see a balance, and withdraw to their bank account. The key management question is interesting to us; it's a distraction to them.

This isn't a failure of education. It's a correct prioritization. A restaurant owner who wants to accept USDC from international customers is not going to become a Stellar developer to do it. If we require that, we lose the customer.

## Our compromise

Approach A: managed wallets by default. Every merchant who signs up gets a Stellar account provisioned automatically. They can take payments immediately. The keys are in our secure enclave, the funds are on-chain in their account.

The upgrade path is real and documented: merchants can export their keys and take self-custody at any time. We're building passkey-derived key management as an opt-in for merchants who want self-custody without the seed phrase UX. BYO wallet is always available for merchants who already have Stellar accounts.

The marketing copy adjustment: we don't say "non-custodial" without qualification. We say "settlement on-chain, managed wallets out of the box." That's accurate. The funds are on-chain. We manage the keys. Merchants who care about the distinction can read the docs and make an informed choice.

The Twitter-cohort will say we compromised. The Stripe-cohort will say we shipped.
40 changes: 40 additions & 0 deletions apps/www/content/blog/no-fx-spread.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: "We don't take an FX spread. Here's what we do instead."
category: "Engineering"
author: "Mira Adeoye"
date: "2026-04-02"
excerpt: "30 basis points, transparent, on the conversion line of the receipt. Not buried in the rate."
readTime: "3 min"
---

30 basis points, transparent, on the conversion line of the receipt. Not buried in the rate.

## The standard processor model

Most payment processors make money two ways: a visible processing fee (e.g., 2.9% + $0.30) and a hidden FX spread. The spread is the gap between the mid-market rate and the rate they quote you. It's typically 1–3% on cross-currency transactions.

The spread is invisible to the merchant. It shows up as a slightly worse rate than the one on Google Finance. Most merchants don't notice. The ones who do notice can't easily quantify it, because the mid-market rate at the moment of the transaction isn't on the receipt.

This is not fraud. It's standard practice. But it's not transparent.

## Our model

We use the mid-market rate for every conversion. The rate we quote is the rate you'd get on a currency exchange at the moment of the transaction. We don't mark it up.

Our fee is 30 basis points on the conversion amount, shown as a separate line on the receipt. If you're converting $1,000 of USDC from Ethereum to USDC on Stellar, the fee is $3.00. It's on the receipt. It's in the webhook payload. It's in the settlement report.

## Why we can do this

We don't run a market-making book. We're not taking the other side of the trade. CCTP V2 is the rail: USDC is burned on the source chain and minted on the destination chain. There's no FX exposure for us to hedge.

The "FX spread" that traditional processors charge is partly a hedge against rate movement and partly margin. We don't have rate movement to hedge (USDC/USDC), so we don't need the spread.

Our 30 basis points covers our operational costs and margin. It's a simpler model, and it's possible because we chose a stablecoin-native architecture.

## Why merchants prefer it

Two reasons. First, it's predictable. A merchant who processes $100,000/month knows their Useroutr fee is $300. They can budget for it. They can put it in a spreadsheet. They can explain it to their CFO.

Second, it's separable for accounting. The conversion fee is a distinct line item, not embedded in the rate. For merchants who need to account for payment processing costs separately from FX costs — which is most businesses with a finance team — this matters. The fee goes in one bucket. The conversion goes in another. The receipt makes this easy.

Transparent pricing is a product decision. We made it because we could, and because the merchants we want to work with are the ones who care about it.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: "Why we picked CCTP V2 over Circle Gateway"
category: "Engineering"
author: "Lukas Vogel"
date: "2026-05-20"
excerpt: "When Circle shipped Gateway in May 2026, we evaluated whether to rebuild our cross-chain story around it. We didn't. Here's the actual decision."
readTime: "6 min"
---

When Circle shipped Gateway in May 2026, we evaluated whether to rebuild our cross-chain story around it. We didn't. Here's the actual decision.

## The product gap

Gateway is a compelling product for a specific use case: merchants who want to accept crypto payments and receive fiat. It handles the conversion, the compliance, and the settlement. For that use case, it's excellent.

But Stellar isn't on Gateway mainnet. That's not a minor footnote for us — Stellar is our settlement hub. Every payment we process routes through Stellar's path payment system. The economics of our fee model depend on Stellar's liquidity pools. Our managed wallet infrastructure is built on Stellar's account model.

Gateway's chain support at launch: Ethereum, Base, Solana, Polygon. Stellar: not on the roadmap for mainnet.

## The model mismatch

Gateway is designed around a pre-deposit model. Merchants fund a Gateway account, and Circle handles the conversion and settlement from that float. It's a clean UX for the merchant, but it means Circle is holding funds — which means the merchant is exposed to Circle's credit risk, and Circle needs to be a money transmitter in every jurisdiction where the merchant operates.

Useroutr's model is different. We don't hold funds. Settlement happens on-chain, atomically, in the same transaction that moves money from the payer to the merchant. There's no float, no credit exposure, no custody.

CCTP V2 fits this model. It's a burn-and-mint protocol: USDC is burned on the source chain, an attestation is issued by Circle's Iris service, and USDC is minted on the destination chain. We call the contracts; Circle operates the attestation service. No pre-deposit, no float, no custody.

## What Stripe is doing

Stripe added CCTP V2 support in Q1 2026. They didn't add Gateway. That's a signal worth paying attention to. Stripe's payments team has more context on the tradeoffs between these two models than almost anyone, and they chose the burn-and-mint primitive over the managed-float product.

Our read: CCTP V2 is the rail. Gateway is a product built on top of a different model. For infrastructure builders, the rail is what matters.

## When we'd revisit

If Stellar lands on Gateway mainnet and Circle adds a non-custodial settlement path, we'd look again. The developer experience on Gateway is genuinely better than wiring CCTP V2 directly — Circle has done a lot of work to make the integration surface clean.

But "better DX on a model that doesn't fit" isn't a reason to switch. We'll keep watching the Gateway roadmap. For now, CCTP V2 is the right call.
7 changes: 5 additions & 2 deletions apps/www/next.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { NextConfig } from "next";
import createMDX from "@next/mdx";

const withMDX = createMDX({});

const nextConfig: NextConfig = {
/* config options here */
pageExtensions: ["ts", "tsx", "mdx"],
images: {
remotePatterns: [
{
Expand All @@ -12,4 +15,4 @@ const nextConfig: NextConfig = {
},
};

export default nextConfig;
export default withMDX(nextConfig);
6 changes: 6 additions & 0 deletions apps/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,26 @@
"dependencies": {
"@base-ui/react": "^1.2.0",
"@gsap/react": "^2.1.2",
"@mdx-js/loader": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@next/mdx": "^16.2.6",
"@radix-ui/react-slot": "^1.2.3",
"@tabler/icons-react": "^3.40.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"framer-motion": "^12.35.1",
"gray-matter": "^4.0.3",
"gsap": "^3.14.2",
"gsap-trial": "^3.12.7",
"lucide-react": "^0.577.0",
"motion": "^12.36.0",
"next": "16.1.6",
"next-mdx-remote": "^6.0.0",
"react": "19.2.3",
"react-dom": "19.2.3",
"react-syntax-highlighter": "^16.1.1",
"reading-time": "^1.5.0",
"shadcn": "^4.0.2",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0"
Expand Down
Loading