Overview How it works Traction Roadmap Documentation Open the app
DobDex/ The protocol, end to end

How an exit
actually clears

Eight chapters, in the order the protocol runs them: how a TRUFA score sets the risk tier, how the auction opens, who the Liquidity Nodes are, what happens when nobody bids, and which of the four Soroban contracts holds each step.

TRUFA scorerisk tierLP quoteUSDC on Stellaranchor off-ramp
The problem
Why this exists

A token nobody will buy
is not a liquid asset

The industry solved issuance and declared victory. But an investor who cannot get out of a position in a solar plant or a fleet of machines has not bought a liquid instrument — they have bought a private placement with a nicer interface.

No secondary market

A holder who needs cash before maturity has one option: find a private buyer themselves, negotiate blind, and hope. Most simply hold something they no longer want.

Prices nobody stands behind

Where a price exists it is usually the issuer's own valuation. Nobody has committed capital at that number, so it tells you what the seller hopes, not what the asset is worth.

AMMs are the wrong shape

A constant-product curve prices a token against inventory. It has no view on whether the machine still runs, whether the operator still reports, or whether the cashflow arrived.

The exit is what makes the entry investable
Retail capital buys an RWA for its yield — but only if it believes it can get out. Build a credible exit and you have not just added a feature; you have made the primary market work. That is the whole thesis of DobDex.
How it works
The protocol

How DobDex works

One asset, one score, one tier, one exit. Everything below is the whole mechanism in the order it actually happens — from how an asset gets priced to what occurs on the day nobody wants to buy.

Chapter 00

Where DobDex sits

DobDex is not a standalone exchange. It is the last stage of a pipeline that already runs on Stellar mainnet: an asset gets validated, tokenized, and starts distributing yield. DobDex is what lets the holder of that position leave before maturity.

Stage 01 · Live

DobValidator

Validation agents review the operator's documents, contracts and reported cashflow, and produce a TRUFA score from 0 to 100.

Stage 02 · Live

Token Studio

The validated asset is tokenized into a pool with participation shares. This is where an investor buys in.

Stage 03 · Live

Distribution

Revenue from the asset is paid out to shareholders in USDC through the distribution contracts, on a schedule.

Stage 04 · In build

DobDex

The holder opens an exit. Liquidity Nodes price it, the settlement router pays USDC, and an anchor turns that into local currency.

What DobDex is

A secondary exit venue. Holders sell positions they already own, for USDC, to Liquidity Nodes who choose to buy them. The protocol's job is to make that trade fair, bounded and observable — not to be the counterparty.

What DobDex is not

Not a redemption window, not a pegged swap, and not a promise of instant liquidity. The oracle prices the asset; the exit price is whatever a Liquidity Node will actually pay for it today.

Chapter 01

How an asset gets priced

Assets do not price themselves. The TRUFA score is produced by DobValidator and travels with the asset. Each Liquidity Node reads it, prices off-chain, and answers with a number it is willing to be held to.

1
Assessment

DobValidator scores the asset

Validation agents review the operator's documentation, contracts and reported cash flows and produce a TRUFA score from 0 to 100. The score answers one question: how much should a stranger trust what this asset says about itself?

trufa_score: u32 // 0 .. 100
2
Publication

The score travels with the asset

The certificate is attached to the asset itself, and its history is public. Anyone pricing that asset — a buyer on the primary market, a Liquidity Node quoting an exit — is reading the same record, before any exit is opened.

trufa_certificate(asset) → score, issued_at
3
Pricing

Each Node turns the score into its own number

How much a score is worth in discount is a judgement, and it belongs to whoever is risking the capital. One Node weights cashflow history, another weights the operator, another simply refuses the asset. The protocol does not arbitrate between them.

off-chain model → the USDC the Node will pay
4
What the chain checks

Not the model — the money behind it

The contracts never re-derive a price. They verify the Node's USDC is really in the vault, that the bid clears the floor the Node itself declared, and that it stays under the exposure ceiling the Node itself set. A wrong model costs the Node, not the seller.

lp_vault.commit(node, asset, amount, discount_bps)
The score prices the asset. It does not price the exit.
A TRUFA score tells you how much confidence the asset's reported performance deserves. It does not tell you what someone will pay you for your position today — that is a liquidity question, answered by Liquidity Nodes bidding real USDC. DobDex keeps these two things separate on purpose, and does not offer a pegged or guaranteed redemption at score value.
Chapter 02

Five tiers, five different exits

Tiers are the shared vocabulary Liquidity Nodes price in, not a rule the chain imposes. They say what a given score band has historically had to pay to find a buyer, and how quickly. Select a tier to see how exits in it tend to clear.

A range, not a price

The tier describes where bids on that score band usually land. Where a given exit actually lands depends on how much capital is competing for it, how large the position is, and what each Node already holds of that asset. Two identical scores can clear at different prices on different days — that is the market working, not a bug.

What is fixed when you open

Tiers can move; your exit cannot be moved underneath you. The reference you declared and the floor you set are written into the exit at open_exit and never change. Nodes re-price freely — that changes what they offer, never what you agreed to accept.

Chapter 03

Anatomy of an exit

Every exit ends one of three ways, and the seller decides which one in two of them. Buying into an asset in the first place happens on Token Studio; DobDex only handles the way out.

Path 1

Take the standing bid

The ordinary path. The seller asked what the position is worth, saw a number they liked, and said yes — without waiting for the window to run out. accept_bid is a separate signature, so a bid is never binding on the seller.

Path 2

Let the window close

Five minutes by default, and the seller can set anything from one minute to a day. At expiry the highest bid settles if it met the floor. close is permissionless — leaving capital committed to a finished auction helps nobody.

Path 3

Queued, publicly

Nothing met the floor. The exit takes a numbered FIFO position visible on-chain and keeps taking bids from there — while an asset has a queue, only the exit at its head can settle. The seller can walk away at any time.

Step by step
1
Open

The holder opens an exit from their wallet

The seller signs with Freighter (or any Soroban-compatible wallet). The tokens move into router escrow in the same transaction, so every bid that follows is against tokens that are demonstrably there. The seller declares two numbers: what they think the size is worth, and the least they will take for it.

open_exit(seller, asset, amount, reference_usdc, min_accept_usdc, duration?)
2
Quote

Liquidity Nodes answer with absolute USDC

Each Node prices off-chain — the asset's TRUFA score, its own model, whatever the primary market is doing — and names a number. Absolute, not a discount: whatever the seller declared as a reference, a Node can only ever be held to the figure it named itself. Each bid must beat the standing one.

place_bid(node, exit_id, usdc_amount) // must beat the standing bid
3
Back it

A quote cannot be shown and then withdrawn

The auction checks nothing about the Node's model and everything about its money. Every bid commits real USDC in lp_vault at the moment it is placed — free balance and the Node's own exposure ceiling for that asset both have to allow it. The previous best bid is released in the same call.

lp_vault.commit(node, asset, usdc_amount) // or the bid never lands
4
Clear

Best bid wins — or the exit takes its place in line

The seller can accept the standing bid at any point, or let the window close and take the highest. Either way it is measured against their min_accept_usdc. If nothing clears it, the exit is not force-filled at a bad price: it moves to fifo_queue with a public position and keeps taking bids from there. The seller keeps their tokens and their option to cancel.

below the floor → fifo_queue.enqueue(asset, exit_id) → emits exit.queued
5
Settle

One transaction moves everything

settlement_router.settle transfers the participation tokens to the winning Liquidity Node, the USDC to the seller net of the discount and protocol fee, and emits exit.settled with the full breakdown. Soroban's atomicity means there is no state where one leg happened and the other did not. A seller who wants fiat continues into an Anchor Platform withdrawal from the same USDC balance.

settle(exit_id) → tokens → LP | USDC → seller | fee → treasury
Chapter 04

Who provides the exit capital

A Liquidity Node is anyone willing to buy someone else's RWA position at a discount they set themselves. Permissionless to join, explicit about risk appetite per asset, and never filled on something they did not name.

Phase 1

Deposit

Send USDC to lp_vault and become a Node. It stays yours and stays free until you put it behind a bid.

USDC on Stellar
Phase 2

Declare appetite

Per asset: the minimum discount you require and your maximum exposure. No appetite set means no fills — you are never matched into something you did not name.

set_appetite(asset, min_bps, max_exposure)
Phase 3

Bid & win

Name a number on any open exit. Win and you receive the participation tokens at your own price — a yield-bearing position bought below what the seller called it worth.

exit.bid → exit.settled
Phase 4

Hold or re-exit

Keep collecting the asset's distributions, or open your own exit later and let the next Node price it. Nodes are not locked into what they buy.

distributions in USDC

Node parameters

set_appetite(asset, …)
Standing terms, declared per asset. An asset you have set no appetite for is an asset you cannot be filled on — silence is a refusal, not a default yes.
min_discount_bps
The floor return you require to part with capital, checked against the discount your bid implies. It is your own limit, held against you by the vault so a fat-fingered bid cannot clear.
max_exposure
A per-asset ceiling on how much of a single RWA you can accumulate. It keeps counting after a payout, because you are then holding the asset — only you can mark a position divested.
free_balance
Not a setting: deposited − committed − pending_withdrawal. Real USDC the contract holds. It is the solvency invariant, and nothing bypasses it.

Withdrawing capital

Uncommitted capital
Anything not backing an open bid or an in-flight settlement can be withdrawn after the standard timelock. The delay exists so a Node cannot pull liquidity between bidding and settling.
Capital behind a live bid
A withdrawal request reserves the amount immediately, so it stops counting as free balance the moment you ask. What is already committed to a standing bid stays committed until that bid is beaten, settled or released — otherwise a quote could be shown and then withdrawn.
Chapter 04b

The Pooled Liquidity Node

Not everyone wants to manage tier appetites and bid on individual exits. The Pooled Node is a shared vault position that does it on behalf of its depositors.

How it works

One position, many depositors

The Pooled Node registers as a single Liquidity Node in lp_vault. Depositors contribute USDC and receive shares; the operator sets the tier appetite and bidding strategy for the whole position. Depositors get exposure to exit spreads without running a bidding operation.

Share-based

Proportional in, proportional out

Positions acquired through winning bids, and the distributions they generate, accrue to shareholders in proportion to their shares. Redemption is against the pool's share of vault capital plus the assets it currently holds.

Passive participation

Deposit USDC, receive shares. No bidding, no per-asset parameters to maintain.

Managed strategy

The operator adjusts which tiers to serve and at what discount as conditions change.

Multiple pools

Nothing stops several Pooled Nodes existing side by side with different risk mandates.

Chapter 05

When nobody bids

Most RWA venues have no answer for this case, which is why their liquidity claims break the first time an asset gets uncomfortable. DobDex makes the unfilled case an explicit, public protocol state.

5 min
bidding window closes
no bid
#4
public FIFO position
You keep your tokens

A queued position is still yours and still earns whatever the underlying asset distributes while it waits.

Your position is visible

Queue depth and your place in it are readable on-chain by anyone. No private list, no discretionary reordering.

You can leave

Withdraw from the queue at any time and re-open later at a different threshold, or hold the asset to maturity.

Why a visible queue matters more than a bigger promise
A venue that always claims instant liquidity is making a promise it cannot keep on a bad day, and the moment it breaks, everyone learns their exit was never real. A queue with a public position is a smaller promise that survives contact with reality — and it is the honest input a buyer needs when deciding what an asset is worth in the first place.
Chapter 06

Four Soroban contracts

The exit layer is deliberately small and separable. Each contract owns one decision and emits typed events. Their error codes are disjoint — 1–99, 100–199, 200–299, 300–399 — so a refusal that surfaces through a cross-contract call still says which contract said no, instead of decoding as the caller's own error with the same number. Source on GitHub.

How the four exit contracts call each other Any wallet calls exit_auction. exit_auction asks lp_vault whether the Node's capital is really free, asks settlement_router to move the tokens and the USDC, and asks fifo_queue to record who was waiting first. exit_auction itself holds no funds. any wallet exit_auction owns the lifecycle open_exit · place_bid · accept_bid close · cancel ERRORS 300–399 capital check moves value records the wait lp_vault ERRORS 1–99 is the Node’s USDC really free? deposit · set_appetite · commit · pay_out settlement_router ERRORS 100–199 move both legs, or revert both escrow · settle · refund · quote_net fifo_queue ERRORS 200–299 who was waiting first enqueue · dequeue · position_of · head tokens → Node USDC → seller
Only one of these four contracts can move money. exit_auction owns the lifecycle and holds no funds: it cannot transfer a token, cannot pay a seller, and has no function that reorders the queue. Solvency is answered by lp_vault before a bid is accepted, and both legs of a fill are executed by settlement_router in one Soroban transaction — so there is no state where the tokens moved and the USDC did not. The disjoint error ranges mean a refusal surfacing through a cross‑contract call still names the contract that said no.
lp_vaultIn build

LP Liquidity Vault

Where Liquidity Nodes deposit USDC and declare, per asset, the minimum discount they require and the most of it they will hold. Free balance is the solvency invariant and nothing bypasses it. 17 tests · errors 1–99

deposit / set_appetite / commit / pay_out
settlement_routerIn build

Settlement Router

The only contract in the layer that moves value. Escrowed tokens have exactly two exits: to a Node that paid for them, or back to the seller. There is no admin path to them, at any fee. 12 tests · errors 100–199

escrow / settle / refund / quote_net
fifo_queueIn build

FIFO Queue Manager

When demand for the door exceeds the capital standing behind it, exits wait instead of racing. Position is public, leaving is always allowed, and there is no function anywhere that reorders the line — not for the admin either. 7 tests · errors 200–299

enqueue / dequeue / position_of / head
exit_auctionIn build

Exit Auction Engine

The lifecycle, and the only caller the other three accept. It holds no funds itself: the vault knows whether a Node's capital is really there, the router performs the transfer or reverts, and the queue records who was waiting first. 15 tests · errors 300–399

open_exit / place_bid / accept_bid / close / cancel

Typed events, indexed end to end

Every state change emits a typed Soroban event. An indexer subscribed to Soroban RPC reconstructs the entire history of exits, bids and vault movements without trusting our API.

exit.openedA position is on the block and the tokens are escrowed. Carries the asset, the size, the seller's declared reference and their floor.
exit.bidA Node put capital behind a price. Carries the absolute USDC and the discount it implies — the discount is descriptive, the USDC is what binds.
exit.settledOne transaction moved everything: tokens to the Node, USDC to the seller net of discount and fee, fee to the treasury.
exit.queuedNothing met the floor. Carries the FIFO position assigned and the queue depth at that moment.
exit.cancelledThe seller withdrew. Bids are conditional at fill time, so nobody was owed anything.
vault.deposit / vault.withdrawA Node added USDC, or capital left after the timelock and the free-balance check.
vault.committed / vault.releasedCapital locked behind a live bid, then freed because the bid was outbid, cancelled or expired.
vault.paid_outCapital actually left the vault to pay a seller — the only event in the pair that is not reversible.
Already proven on this stack
The Soroban event indexer is not speculative work — Dobprotocol already runs one against Stellar mainnet for its tokenization contracts, with 412 contract events indexed across 125 live pools. The DobDex build extends that same pipeline to the exit contracts rather than starting a new one.
Chapter 07

Safety rails

The failure modes that matter for an exit venue are a quote nobody can honour, a seller filled at a price they never took, a queue somebody pays to skip, and an admin who can reach the money. Each has a specific rail, and none of them is a promise — they are all checks.

The seller's floor, in absolute USDC

Every exit carries a min_accept_usdc. A bid below it cannot settle — the exit queues instead. And a bid is only ever an offer: accepting it is a separate signature, so sellers are never force-filled at a price they did not take.

min_accept_usdc in open_exit

Free balance is the invariant

deposited − committed − pending_withdrawal. Real USDC the contract holds, checked before any bid is accepted. Nothing in the layer bypasses it, which is why a Node cannot show a quote it cannot honour.

free_balance ≥ bid

Bounded window, seller's choice

Five minutes by default, floored at one and capped at a day. The seller sets it when they open; nobody else can move it afterwards, and close is permissionless so a finished auction cannot be held open to strand a Node's committed capital.

60 ≤ duration ≤ 86,400 · default 300

Escrow has exactly two doors

Tokens locked by the router can only leave towards a Node that paid for them, or back to the seller. There is no admin path to them at any fee, and settlement is one atomic Soroban transaction — there is no state where one leg happened and the other did not.

settle → node  |  refund → seller

The line cannot be bought

While an asset has a queue, only the exit at its head can settle. Bidding on the others stays open, but nobody buys their way past a seller who has been waiting — and no function anywhere reorders the line, not for the admin either.

not_at_head → settlement refused

Withdrawal timelock

Node withdrawals are requested, not taken. The amount stops counting as free balance the moment it is requested, so liquidity cannot be pulled out from under a bid that is already standing.

request → unlock_at → execute

Exposure keeps counting after the fill

A Node's per-asset ceiling does not reset when it pays out — it is then holding the asset. Only the Node can mark a position divested, so the number it is trusting is its own. Lying here risks its capital and can never make the vault insolvent.

reduce_exposure, by the node only

A refusal says who refused

Error codes are disjoint across the four contracts. A bid rejected by the Node's own vault terms and a bid rejected by the auction are different failures, and they never decode to the same thing.

1–99 · 100–199 · 200–299 · 300–399

What the admin can and cannot do

The admin sets the wiring — which auction the vault answers, the treasury address, the protocol fee within a hard MAX_PROTOCOL_FEE_BPS of 500. It cannot price an exit, reorder the queue, or reach escrowed tokens.

fee ≤ 500 bps, enforced on-chain

Audit & monitoring plan

The four contracts ship with 51 tests that link the real peers and run the layer end to end, and a written threat model covering vault insolvency, escrow reachability, queue manipulation and admin-key compromise. Monitoring alerts on abnormal queue growth, exits closing into the queue at unusual rates, and any config change. The contracts are open source with Cargo.lock committed for reproducible SEP-55 builds, and the event stream is public — so the monitoring we run is monitoring anyone can reproduce. Nothing is deployed yet.

Try it

Price your exit

Move the score and the ticket size to see roughly what a Liquidity Node would pay for the position today. Illustrative — every Node prices off-chain, so the real number is whatever a Node actually bids.

B
Standard120 – 300 bps band
82/100
TRUFA score
E · distressed D · 45 C · 60 B · 75 A · 90
Exit size$25,000
$500$500K
Competing capitalNormal
Settles in
USDC on Stellar, one Soroban transaction, seller-side floor enforced by the Settlement Router. Cash out through an Anchor Platform off-ramp.
Estimated net proceeds
24,813USDC
on a $25,000 position — you keep 97.42%
ProceedsDiscount · 2.58%
Inside the discount$645
Tier spread what this risk costs2.00%
Size impact ticket vs. standing appetite0.33%
Protocol fee capped at 500 bps on-chain0.25%
Bid accepted
Minutes
Window closes
~5 min
Queued
Hours – days
The score travels with the asset DobValidator issues it; Nodes read it and price off-chain. No contract re-derives it.
Tiers are vocabulary, not rules Nodes bid absolute USDC. The chain only checks the money is really there.
Best bid wins the window Below the seller's floor nothing is force-filled — the exit takes a public place in line.
Size is priced, not curved The impact above reflects standing appetite for that asset, not an AMM depth function.

Illustrative model, not a quote. Real prices are posted by Liquidity Nodes and can differ in either direction; DobDex does not guarantee a price or a fill, and never buys the position itself.

Built on Stellar
Ecosystem

What we build on

DobDex is deliberately not a self-contained island. Each piece of the exit path that Stellar already solves well is delegated to the ecosystem primitive that solves it.

Soroban

Build target

All four contracts are Rust on Soroban. Atomic multi-step settlement, typed events and predictable fees are the reason the exit path can be a single transaction instead of a choreography.

execution layer

DeFindex

Integration

Liquidity Node capital sitting in the vault waiting for exits should not sit dead. DeFindex strategies put idle reserve capital to work, so the opportunity cost of standing ready is lower — which is what makes deeper reserves economically rational.

idle capital yield

Blend v2

Integration

A Node that wants to bid on an exit without unwinding another position needs credit. Blend lets Nodes source short-term liquidity against collateral instead of keeping every dollar of bidding power idle in the vault.

node leverage

Anchor Platform

Integration

An exit that ends in USDC is only half an exit for an investor who needs local currency. The settlement router hands off to Anchor withdrawal flows so the last mile is fiat in a bank account, not another token to figure out.

fiat off-ramp

USDC on Stellar

Live

The single settlement asset for the entire protocol. Bids, fills, fees and queue positions are all denominated in it, so there is no second exchange-rate risk hidden inside the exit.

settlement asset

EVM reference build

Reference only

An earlier version of this design was built and tested against EVM. It de-risks the mechanism — the auction, tiering and queue logic have run before — but it is not the production target and is not where DobDex ships. Stellar is.

prior art
Where we are
Traction

Not starting from zero

DobDex is being built on top of a protocol that already runs on Stellar mainnet. These are production database figures, not projections.

125
Live pools on Stellar mainnet
878
Registered users · 482 managed wallets
147
Marketplace listings & settled purchases
412
Indexed Stellar contract events
Roadmap
Three milestones

What we are building

Three milestones from a working MVP to mainnet, each ending in something verifiable on-chain rather than a status update.

Milestone 01Next

MVP & core contracts

Soroban testnet
  • LP Liquidity Vault taking USDC deposits and per-asset appetite from Liquidity Nodes
  • Settlement Router escrowing tokens and clearing a fill in one atomic transaction
  • Open → bid → accept path working end to end against test pools
  • Exit interface and LP dashboard wired to Freighter
Milestone 02Then

Auctions, queue & integrations

Full testnet build
  • Exit Auction Engine with a bounded window and competitive LP bidding
  • FIFO Queue Manager for the case where demand exceeds available liquidity
  • DeFindex yield routing on uncommitted vault capital; Blend v2 as a second venue
  • Soroban RPC event indexer plus the onchain monitoring plan and threat model
Milestone 03Then

Mainnet & off-ramp

Stellar mainnet
  • All four contracts on mainnet, SEP-55 attested from a reproducible build
  • Anchor Platform integration closing the loop from USDC to local currency
  • Real exits from live Dobprotocol pools with real Liquidity Node capital
  • Public dashboards for fills, spreads, queue depth and Node capacity
Backed by
Stellar Draper University Uniswap Foundation eHive

Exit liquidity, on Stellar

Step through the mechanism in the simulator, watch the product walkthrough, or explore the live Dobprotocol pools that DobDex is being built to serve.

Open the app Read how it works