engineering

Cross-Border Payments on Localhost

Sending $100 from New York to Berlin touches six institutions and takes two days. A prototype on localhost does it in one transaction hash.

By Alex Kugell ·

Sending $100 from a business in New York to a supplier in Berlin starts at a sending bank, passes through one or two correspondent banks holding Nostro/Vostro accounts, hits an FX desk that may or may not be in the same time zone, and lands at the receiving bank. Four institutions minimum. Each one charges a fee, logs its own version of the truth, and settles in its own batch window.

Total spread: 200 to 400 basis points. Total time: one to three days. For $100.

J.P. Morgan's Kinexys platform now processes $2 billion daily in tokenized deposits. Mastercard paid $1.8 billion for BVNK, a stablecoin orchestration layer handling $30 billion a year across 130 countries. The tokenized money market has crossed $300 billion.

The infrastructure replacing correspondent banking is being built right now. What does the architecture actually look like at the engineering level?

You can answer that by building a working version on a laptop. A Postgres ledger, a permissioned AMM on a local EVM chain, tokenized USD and EUR, and a backend that orchestrates KYC, on-ramp, swap, and off-ramp. The full cross-border flow, end to end, in a single repo.

The dual-ledger constraint

The first design decision is the one that separates this from a DeFi toy. Real money lives in a bank ledger. Tokenized money lives on a chain. A cross-border payment system needs both, and they have to stay in sync.

The bank side looks like every core banking abstraction you've seen. A FiatLedgerService sits on Postgres and exposes three operations: get balance, credit, debit.

When a user on-ramps $100, the fiat ledger debits their USD account and the backend mints 100 USDx tokens to their wallet on-chain. When they off-ramp, the backend burns the tokens and credits the fiat ledger.

async creditAccount(userId, currency, amount) {
  return prisma.fiatAccount.upsert({
    where: { userId_currency: { userId, currency } },
    update: { balance: { increment: amount } },
    create: { userId, currency, balance: amount },
  });
}

This is the constraint that production systems like Kinexys solve at scale. The chain is not the source of truth for money. It's the source of truth for where the tokenized representation is. The bank's balance sheet remains the liability record.

Every mint and burn must correspond exactly to a debit and credit on the other side, or the two ledgers drift apart.

Reconciliation in a traditional correspondent banking chain is an archaeological dig through siloed systems.

In a tokenized model, reconciliation becomes an assertion: either the token supply matches the bank's liabilities, or it doesn't. Either this wallet holds 92 EURx, or it doesn't.

That visibility has its own cost. Every position is on-chain, in a common format, which means every position is also readable by anyone with access to the chain. Permissioning the chain solves this for a consortium. It doesn't solve it for a public network.

FX as a function call

The FX conversion is where this architecture diverges most from the traditional model. Instead of an order book, an FX desk, or a request-for-quote flow, an automated market maker holds reserves of both currencies and prices swaps mathematically.

A constant-product AMM with a 0.1% fee in 60 lines of Solidity:

function swapUSDxForEURx(uint256 amountIn, uint256 minAmountOut)
    external returns (uint256 amountOut)
{
    uint256 amountInWithFee = amountIn * (10000 - FEE_BPS) / 10000;
    amountOut = (amountInWithFee * reserve1) / (reserve0 + amountInWithFee);
    require(amountOut >= minAmountOut, "Slippage too high");
 
    token0.transferFrom(msg.sender, address(this), amountIn);
    token1.transfer(msg.sender, amountOut);
 
    reserve0 += amountIn;
    reserve1 -= amountOut;
}

From the backend's perspective, FX becomes a deterministic function call. Put in X dollars, get back Y euros, in a single transaction hash.

The correspondent chain, the batch windows, and the hidden spread all collapse into the pool's fee.

In production, this model has limits. A constant-product curve means large trades move the price. Institutional FX needs concentrated liquidity around the real exchange rate, oracle-fed pricing, or hybrid order book designs.

The 0.1% fee on a $10 million trade is $10,000, which is competitive with correspondent banking but not with prime brokerage FX. The AMM works for retail-scale cross-border payments. Replacing wholesale FX requires different curve mathematics.

The orchestration pipeline

A single cross-border payment touches every layer of the system in sequence. The backend orchestrates it as a pipeline, and every step emits an auditable event:

// Step 1: KYC check — is sender approved?
// Step 2: On-ramp — debit fiat, mint tokens
// Step 3: AMM swap — USDx to EURx
// Step 4: Transfer — EURx to receiver wallet
// Step 5: Off-ramp — burn tokens, credit fiat
// Step 6: Audit log — write event for every step

In a SWIFT world, these steps are scattered across institutions, message formats, and time zones. Each institution maintains its own version of the truth, and reconciling across them is where the two-day settlement delay lives.

In this model, the pipeline completes atomically. Either every step succeeds or nothing moves.

The audit trail is a side effect of the architecture, not an afterthought. Every on-ramp, swap, transfer, and off-ramp writes an event with a type, a timestamp, and a transaction hash.

A compliance team reviewing a cross-border payment can reconstruct the full flow from a single query, not from correlating SWIFT MT messages across three banks.

Where the prototype breaks down

A working prototype reveals the production constraints a whitepaper hides.

KYC lives in two worlds. In the prototype, KYC is a status field in Postgres checked at the API layer. In production, it becomes an on-chain whitelist contract fed by off-chain KYC processes, queried by the AMM and every protocol contract before allowing a transaction.

The whitelist contract is simple. The governance model and attestation format behind it are not.

Key management is the real security surface. The prototype uses Anvil's default private key. Production requires HSMs, multi-party computation, and key rotation policies.

The backend that mints and burns tokens holds the keys to the entire money supply. Securing that signer is a harder problem than building the AMM.

Credit risk between institutions disappears from the slide. Correspondent banking exists partly because banks extend credit to each other across time zones. An atomic settlement model removes that credit extension, which is good, but it also means every participant needs pre-funded positions. The liquidity management problem shifts rather than disappears.

AML at the transaction level is missing. The prototype checks KYC at on-ramp. Production requires transaction-level monitoring, sanctions screening on every transfer, and suspicious activity reporting. The on-chain visibility makes some of this easier since every flow is traceable, but the monitoring infrastructure still needs to be built.

Each of these gaps represents months of engineering in a production system. The prototype's value is in making those gaps specific and concrete rather than abstract.

What the architecture proves

The same architecture that runs on localhost, a fiat ledger, tokenized deposits, an AMM, atomic settlement, and auditable events, is the architecture that J.P. Morgan, Mastercard, and a growing consortium of banks are building at scale.

The pieces are not speculative. Tokenized deposits are live. AMMs are battle-tested on public chains processing billions in volume. On-chain audit trails are running in production.

The engineering question is no longer whether this architecture works. It's how to bridge the gap between a working prototype and the regulatory, operational, and security requirements of moving real money between real institutions.

Cross-border correspondent banking costs 200 to 400 basis points and takes days because the trust model requires a chain of bilateral relationships. A tokenized model replaces that chain with a shared ledger, a programmable FX layer, and atomic settlement.

The spread drops to the pool's fee. Settlement goes from days to a single transaction. Reconciliation stops being a job someone does manually.

The repo runs on localhost:8545. The architecture runs at the largest banks in the world. The gap between them is operational, not conceptual.

Sources

Built by Trio, a fintech-native engineering partner helping teams build the next generation of financial technology and infrastructure.

Subscribe to Ledger Drift for high-signal insights into how modern fintech is built, from systems to code to teams.

Keep reading

fintechWhat Agent Authentication Actually RequiresThree approaches to the same problem are shipping simultaneously. One already processed a real transaction.
analysisCircle Bought Its Own Network MemberCircle promised it would never compete with its CPN partners. Then it paid $400 million for one of them.
analysisFintechs Are Done Renting BanksChime bought Stride Bank for $590 million. Revolut got its US charter. Block applied for one. Three in three months.
View more ›