Stellar Community Fund — Build Award · Integration Track

Excalibur Soroban PvP Settlement
Technical Architecture

Project Excalibur — Competitive PvP Arena
Submitter Excalibur (Delaware C-Corp, incorporation in progress)
Live product launch.excalibur.game — running on Base (EVM L2) with USDC settlement via the Thirdweb stack
Stellar build target Soroban as a parallel deployment for EURC settlement and MiCA-compliant European expansion, aligned with Korea Blockchain Week (Oct 1, 2026)
Document version v2.0 — for SCF reviewer evaluation

Excalibur is a competitive PvP gaming arena where two players stake USDC or EURC and fight in real-time matches. Every kill resolves into an atomic transfer from loser to winner. Outcomes are deterministic and skill-based. The product is live on Base today, with the Thirdweb stack handling wallet, deployment and SDK layers for the EVM side. This document specifies how Excalibur extends to Stellar/Soroban as a parallel settlement layer — not a migration — to unlock MiCA-compliant EURC settlement for the European market, what gets built, what gets integrated, and how on-chain activity is made verifiable to reviewers.

Why Stellar specifically — and why a parallel deployment, not a migration. A single PvP match generates 10 to 30 micro-payouts (kills + final settlement). Sub-cent fees + 5-second finality + native USDC/EURC make this unit-positive. Base handles the global USDC-paying audience well through Thirdweb's account abstraction and L2 economics. What Base cannot offer is MiCA-compliant EUR settlement, which is the unlock for the European audience. EURC on Stellar is the only consumer-ready, MiCA-compliant euro stablecoin in production today. Rather than migrate away from a working Base deployment, Excalibur extends to Stellar in parallel: USDC matches stay on Base, EURC matches settle on Soroban, both routed transparently through the same client.

0Dual-deployment architecture: why both chains

The single most important framing of this build: Excalibur is NOT migrating from Base to Stellar. The Base deployment keeps running. Soroban is added as a parallel, asset-scoped settlement layer.

ConcernBase (current, Thirdweb stack)Stellar / Soroban (this build)
Primary audienceGlobal, USDC-native players, KR/NA/APACEuropean players settling in EURC under MiCA
Settlement assetUSDC (Base SAC)EURC (Stellar Asset Contract) + USDC for fallback
Smart contractsSolidity, deployed via ThirdwebRust → WASM, deployed via Soroban CLI
Wallet integrationThirdweb Connect (Metamask, Coinbase Wallet, WalletConnect)Stellar Wallets Kit (Freighter, Albedo, LOBSTR, xBull) + Privy for email/Google
Account abstraction / gaslessThirdweb AA (smart accounts on Base)Stellar fee-bumping (sponsor pays fees)
Team ownershipExisting Lead Dev (Thomas) + team — already shippingDedicated Soroban / Rust engineer hire (financed by this grant) + Thomas as integration owner

The Unity client routes a player's match to the chain that matches their funding asset: a USDC player hits the Base MatchEscrow.sol; an EURC player hits the Soroban MatchEscrow.rs. From the player's perspective, the experience is identical. From the protocol's perspective, two contracts exist and each chain serves the audience it is best suited for.

What this grant funds, explicitly: the Soroban half of this dual deployment. The Rust engineer hire, the MatchEscrow.rs contract development, the Stellar Wallets Kit + Privy integration, the EURC asset wiring, and the mainnet pilot at KBW. The Base deployment continues on its own existing engineering and capital track.

1System overview

The architecture combines an offchain low-latency match server (preserves in-game UX) with an on-chain Soroban settlement layer (preserves trust and verifiability). Kill events are signed offchain by the game server during the match and batched to Soroban every 5 seconds.

┌───────────────────────────────────────────────────────────────────────────────┐ │ EXCALIBUR CLIENT (UNITY) │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ │ │ Gameplay Loop │ │ Wallet Layer │ │ │ │ (PvP combat, kills) │ │ ├ Stellar Wallets Kit │ │ │ └─────────────────────────┘ │ │ (Freighter, Albedo, LOBSTR, xBull) │ │ │ │ └ Privy embedded wallets │ │ │ │ (email / Google → custodial Stellar) │ │ │ └─────────────────────────────────────────┘ │ └──────────┬───────────────────────────────────────────────┬────────────────────┘ │ kill events │ deposit / withdraw │ (signed match state) │ transactions ▼ ▼ ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ EXCALIBUR GAME SERVER │ │ STELLAR / SOROBAN │ │ (offchain, low-latency) │ │ │ │ │ │ ┌───────────────────────┐ │ │ ├ match orchestration │ │ │ MatchEscrow.rs │ │ │ ├ anti-cheat │ signed kill │ │ (Soroban contract) │ │ │ ├ kill receipt signing │───batches────►│ │ │ │ │ │ (Ed25519, every 5s) │ (Horizon) │ │ ├ init() │ │ │ └ dispute window manager │ │ │ ├ deposit() │ │ │ │◄─verification─│ │ ├ resolve_kill() │ │ │ │ results │ │ ├ finalize_match() │ │ └──────────────────────────────┘ │ │ └ timeout_refund() │ │ │ └──────────┬────────────┘ │ │ │ Atomic Splits │ │ ▼ │ │ ┌───────────────────────┐ │ │ │ Stellar Asset Contract│ │ │ │ USDC · EURC │ │ │ └───────────────────────┘ │ └────────────┬─────────────────┘ │ ┌─────────────────────────────┴────────────────┐ │ │ ┌─────────▼──────────┐ ┌───────────▼──────────┐ │ Stellar Broker │ │ Anchor Platform │ │ (multi-asset │ │ (fiat → USDC ramp, │ │ funding layer) │ │ EU and KR rails) │ └────────────────────┘ └──────────────────────┘

2What we build vs what we integrate

Reviewers consistently ask for this split, so we make it explicit upfront. The core innovation is on the BUILD side. The INTEGRATE side extends the user-facing surface using existing Stellar building blocks. Ownership for the Stellar layer is led by a dedicated Soroban / Rust engineer financed by this grant, working with the existing team (Thomas — Lead Dev, Sam — Unity Front, Briac — Backend) for integration with the Base deployment.

LayerComponentModeOwner
SettlementMatchEscrow.rs Soroban contractBUILD (Rust, MIT)Soroban engineer hire (lead) + Thomas (integration)
SettlementGame server kill batching service for StellarBUILD (Rust/Go)Soroban engineer + Briac
SettlementUnity client Stellar SDK bridgeBUILD (C#)Sam + Soroban engineer
WalletsStellar Wallets Kit (Freighter, Albedo, LOBSTR, xBull)INTEGRATESam
WalletsPrivy embedded wallets (email / Google → Stellar)INTEGRATESam
AssetsEURC (primary) + USDC via Stellar Asset ContractINTEGRATESoroban engineer
FundingStellar Broker (multi-asset funding)INTEGRATESoroban engineer
FundingAnchor Platform (fiat → EURC ramp for EU)INTEGRATESoroban engineer + Titou

3MatchEscrow.rs — Soroban contract

The core innovation. A single contract holds both players' stakes for the duration of a match, resolves kills as atomic transfers between participants, and finalizes the match with a 1% protocol fee. Open-source under MIT license; reusable by any other PvP gaming project on Stellar.

3.1 Contract storage

// MatchEscrow.rs — storage layout (simplified)

pub struct Match {
    pub match_id: BytesN<32>,
    pub player_a: Address,
    pub player_b: Address,
    pub asset: Address,           // USDC SAC or EURC SAC
    pub stake_per_player: i128,   // e.g. 10_000_000 = 10 USDC (7 decimals)
    pub server_pubkey: BytesN<32>,// Ed25519 pubkey of authorized game server
    pub state: MatchState,        // Pending | Active | Settling | Closed
    pub balance_a: i128,
    pub balance_b: i128,
    pub created_at: u64,
    pub last_activity: u64,
    pub timeout_seconds: u64,     // default 600s
}

pub enum MatchState {
    Pending,    // contract created, awaiting deposits
    Active,     // both players deposited, match in progress
    Settling,   // server submitted final state, dispute window open
    Closed,     // funds released to winner + protocol
}

3.2 Public API

impl MatchEscrow {

    // Create a new match. Anyone can call; both players must subsequently deposit.
    pub fn init(
        env: Env,
        match_id: BytesN<32>,
        player_a: Address,
        player_b: Address,
        asset: Address,
        stake_per_player: i128,
        server_pubkey: BytesN<32>,
    ) -> Match;

    // Player deposits their stake. Requires player.require_auth().
    pub fn deposit(env: Env, match_id: BytesN<32>, player: Address);

    // Server submits a batch of signed kill events.
    // Each event: (loser, winner, amount, nonce, signature).
    // Verified on-chain against server_pubkey (Ed25519).
    pub fn submit_kill_batch(
        env: Env,
        match_id: BytesN<32>,
        events: Vec<KillEvent>,
    );

    // Server signals match end. Opens a dispute window of N seconds.
    pub fn finalize_match(
        env: Env,
        match_id: BytesN<32>,
        final_state_signature: BytesN<64>,
    );

    // After dispute window: protocol fee (1%) sent to treasury,
    // remaining balance to winner. Atomic Splits primitive used.
    pub fn settle(env: Env, match_id: BytesN<32>);

    // Either player can claim if server abandons match (after timeout).
    // Refunds via Claimable Balance to avoid contract holding stale funds.
    pub fn timeout_refund(env: Env, match_id: BytesN<32>);

    // Player disputes a specific kill event during the dispute window.
    // Requires proof of out-of-order nonce or invalid signature.
    pub fn dispute(env: Env, match_id: BytesN<32>, evidence: Bytes);
}

3.3 Why Soroban primitives, specifically

Atomic Splits

Native multi-recipient atomic payout. One settle() call pushes funds to winner + protocol treasury in one tx, with one fee. No two-step pattern, no failure recovery code needed.

Claimable Balance

Used for timeout_refund(). If the server abandons a match, players can claim their stake back without the contract holding stale state. The Claimable Balance is the refund vehicle.

Stellar Asset Contract

USDC and EURC both expose a SAC interface on Stellar. MatchEscrow.rs treats them identically — same contract handles both assets via the asset address parameter.

require_auth() + Ed25519 verification

Player authorizations use require_auth() (native Soroban). Server signatures use BytesN<64> Ed25519 verified onchain via env.crypto().ed25519_verify().

4Kill batching: hybrid optimistic UI + on-chain settlement

The most-asked question: how can kills be onchain without breaking gameplay latency? Answer: kills are signed offchain by the game server in <5ms (Ed25519), shown to the player immediately (optimistic UI), then batched to Soroban every 5 seconds. From the player's perspective the kill is instant. From the chain's perspective the kill is final within 10 seconds.

4.1 Sequence — single kill

Player A Player B Game Server Soroban MatchEscrow │ │ │ │ │── shoots ──►│ │ │ │ X dies │ │ │ │── kill event ──►│ │ │ │ │ validate │ │ │ │ (hitreg, anti-cheat)│ │ │ │ │ │◄── XP, sound, instant feedback (optimistic UI) │ │ │ │ │ │ │ │ buffer kill │ │ │ │ (batch of N) │ │ │ │ │ │ │ │ every 5s, sign & │ │ │ │ submit batch ─────►│ │ │ │ │ │ │ │ │ verify Ed25519 │ │ │ │ verify nonces strict-monotonic │ │ │ │ apply atomic transfer │ │ │ │ update balance_a / balance_b │ │ │ │ │ │ │◄──── batch ack ─────│ │ │ │ │

4.2 Why this preserves trust

5End-to-end match flow

Reviewers requested an explicit progression from prototype to live mainnet. Here it is.

[1] Player A and Player B agree to a match │ via lobby UI (existing Excalibur client) ▼ [2] Client calls MatchEscrow.init() │ specifies asset (USDC or EURC), stake amount, server_pubkey │ contract emits MatchCreated event ▼ [3] Both players call deposit() with require_auth() │ wallet signing via Stellar Wallets Kit OR Privy embedded │ contract state → Active ▼ [4] Match begins (gameplay runs in Unity client) │ kills tracked by game server, signed Ed25519, shown to players │ every 5s: server batches signed kills → submit_kill_batch() ▼ [5] Match ends (one player out of stake OR time limit) │ server calls finalize_match() with final state signature │ contract state → Settling, dispute window opens (60s) ▼ [6] After dispute window: │ anyone calls settle() │ contract performs Atomic Split: │ - 99% of winner's balance → winner │ - 1% → protocol treasury │ contract state → Closed ▼ [7] Winner withdraws to wallet (or starts next match with rolled stake)

6Wallet integration paths

Two paths cover the two distinct audiences: crypto-native players (already hold a Stellar wallet) and mainstream gamers (no crypto experience).

6.1 Crypto-native — Stellar Wallets Kit

// Unity-side, C# wrapper over @creit.tech/stellar-wallets-kit (Web)
//   exposed to Unity via a WebView bridge.

var kit = new StellarWalletsKit({
  network: WalletNetwork.PUBLIC,
  selectedWalletId: XBULL_ID,   // or Freighter, Albedo, LOBSTR
  modules: allowAllModules()
});

await kit.openModal({
  onWalletSelected: async (option) => {
    await kit.setWallet(option.id);
    var { address } = await kit.getAddress();
    excaliburClient.setPlayerWallet(address);
  }
});

6.2 Mainstream gamers — Privy embedded wallets

// Sign-in with email or Google → Privy provisions custodial Stellar wallet
//   transparently. Player never sees a seed phrase.

import { PrivyProvider } from '@privy-io/react-auth';

<PrivyProvider
  appId="excalibur"
  config={{
    embeddedWallets: { createOnLogin: 'users-without-wallets' },
    supportedChains: [stellarMainnet],
    loginMethods: ['email', 'google']
  }}>
  <ExcaliburApp />
</PrivyProvider>

For Privy users, the deposit() call still goes through the embedded wallet — the user authorizes the spend via their Privy session, and the SDK signs and submits the Soroban transaction.

7Funding flows

Three funding paths cover all entry points.

PathUser profileStellar building block
Direct USDC depositCrypto-native with existing USDC on StellarStellar Asset Contract (USDC SAC)
Multi-asset depositCrypto-native with XLM or other Stellar assetsStellar Broker (converts on-the-fly to USDC/EURC; contract still receives the settlement asset)
Fiat to USDCMainstream gamer paying with card or SEPAAnchor Platform (EUR/KRW → USDC); for EU users, EURC variant for MiCA compliance

Critically, the MatchEscrow contract logic does not care which path funded the deposit. The settlement asset is always USDC or EURC. The funding layer is decoupled from the contract layer.

8Verifiability checklist for reviewers

Each tranche delivers a specific set of reviewer-verifiable artifacts. We list them here so reviewers know exactly what to look at when they evaluate each milestone.

TrancheVerifiable artifacts
MVP (T1) • Public GitHub repo (MIT license)
• MatchEscrow.rs source + Rust unit test suite passing
• Contract compiled and deployed to local Soroban testnet
• Unity SDK published on GitHub
• Server batching service code public
Testnet (T2) • Public testnet contract address
• Explorer transaction links for: init, deposit, kill batches, finalize, settle
• Video demo of full match flow on testnet
• Stellar Wallets Kit integration screen recordings
• Privy onboarding flow screen recording
Mainnet (T3) • Public mainnet contract address
• Mainnet transaction links for USDC and EURC matches
• Stellar Broker funding transaction links
• Anchor Platform fiat ramp transaction links
• Mainnet activity dashboard (live during KBW)
• Post-launch technical report (volume, gas, latency)

9Stack summary

LayerTech
Smart contractRust + Soroban SDK
Game serverRust (axum) or Go — Ed25519 signing, kill batching, dispute manager
IndexerSoroban RPC + custom event consumer (PostgreSQL)
Unity clientUnity 2022 LTS + custom Stellar SDK (C#) + WebView bridge for SWK
Wallet (web)Stellar Wallets Kit (Freighter, Albedo, LOBSTR, xBull)
Wallet (embedded)Privy with Stellar support
AssetsUSDC (Stellar Asset Contract), EURC (Stellar Asset Contract)
FundingStellar Broker (multi-asset) · Anchor Platform (fiat ramp)
InfraCloudflare for static, AWS for game server cluster, Stellar RPC (Validation Cloud or self-hosted)
Open-source licenseMIT (contract + SDK + batching service)

10Why this matters for Stellar