Marketplace
The marketplace is Token Studio's built-in secondary trading venue. Shareholders can list their pool shares for sale, and investors can browse, discover, and purchase shares across all active pools. All settlements happen on-chain through Stellar Soroban smart contracts.
Access the marketplace: home.dobprotocol.com/marketplace
How It Works
The marketplace follows a simple listing-and-purchase model:
SELLER MARKETPLACE BUYER
| | |
| 1. Create listing | |
| (shares, price, payment token) | |
|--------------------------------->| |
| | 2. Listing visible |
| | on marketplace |
| |<-------------------------------|
| | 3. Buyer selects listing |
| | |
| | 4. Buyer signs purchase TX |
| |<-------------------------------|
| | |
| 5. Shares transferred | 5. Payment transferred |
| from seller to buyer | from buyer to seller |
|<---------------------------------|------------------------------->|
| | |
| | 6. Commission deducted (1.5%) |
| | |
Listing Shares
Creating a Listing
A shareholder creates a listing by specifying:
| Parameter | Description |
|---|---|
| Shares to sell | Number of shares from their holding (1-10,000) |
| Price per share | Price in the chosen payment token |
| Payment token | Token the buyer will pay with (e.g., fUSDC, XLM) |
Listing Rules
- A user can have one active listing per pool at a time
- The listing does not lock or escrow shares -- shares remain in the seller's wallet until purchase
- Listings can be cancelled at any time before purchase
- Each listing receives a unique
sale_addressidentifier (format:SALE_+ 32 hex characters)
Listing Identifier
The sale_address is a randomly generated unique ID, not the pool address:
sale_address: SALE_a1b2c3d4e5f6... (unique per listing)
token_address: CABC123... (pool contract address)
This distinction is important: sale_address identifies the listing, while token_address identifies which pool the shares belong to.
Purchasing Shares
Purchase Flow
- Browse: Buyer visits the marketplace and browses available listings, filtered by pool or across all pools
- Select: Buyer chooses a listing and specifies the number of shares to buy (up to the listed amount)
- Approve: Buyer approves the payment token transfer (if required by the token contract)
- Sign: Buyer signs the purchase transaction with their wallet (Freighter for Stellar)
- Settlement: Smart contract executes the atomic swap -- shares to buyer, payment to seller
- Commission: 1.5% commission deducted from the payment
Purchase Commission
| Component | Amount |
|---|---|
| Share price (per share) | Set by seller |
| Total price | Price per share x number of shares |
| Commission (1.5%) | Deducted from total price |
| Seller receives | Total price - commission |
Example:
Listing: 500 shares at $10/share
Buyer purchases all 500 shares
Total price: $5,000.00
Commission (1.5%): - $75.00
Seller receives: $4,925.00
Buyer receives: 500 shares
Marketplace Views
Browse All Pools
The main marketplace page shows listings across all active pools:
URL: /marketplace
Displays:
- Pool name and ticker
- Number of active listings
- Price range
- Pool performance metrics
Single Pool Marketplace
View all listings for a specific pool:
URL: /marketplace/pool/{pool_address}?network_id={chain_id}
Example:
/marketplace/pool/CABC123...?network_id=10
Displays:
- All active listings for this pool
- Pool details (shares, distributions, APR)
- Listing prices and quantities
- Buy button for each listing
Database Schema
The marketplace uses two tables: one for listings and one for completed transactions.
dob_buy_sales (Listings)
| Column | Type | Description |
|---|---|---|
id | INTEGER | Auto-generated ID |
sale_address | VARCHAR (unique) | Unique listing identifier (SALE_ + 32 hex chars) |
token_address | VARCHAR | Pool address (which pool the shares belong to) |
owner_address | VARCHAR | Seller's wallet address |
payment_token_address | VARCHAR | Token used for payment (SAC address on Stellar) |
price_per_share | DECIMAL | Price per share in the payment token |
shares_amount | INTEGER | Number of shares listed for sale |
chain_id | VARCHAR | Network identifier |
is_active | BOOLEAN | Whether the listing is currently active |
created_at | TIMESTAMP | Listing creation time |
updated_at | TIMESTAMP | Last update time |
dob_buy_sale_transactions (Purchases)
| Column | Type | Description |
|---|---|---|
id | INTEGER | Auto-generated ID |
sale_address | VARCHAR (FK) | References dob_buy_sales.sale_address |
token_address | VARCHAR | Pool address |
buyer_address | VARCHAR | Buyer's wallet address |
shares_amount | INTEGER | Number of shares purchased |
total_price | DECIMAL | Total amount paid |
commission | DECIMAL | Commission deducted |
chain_id | VARCHAR | Network identifier |
created_at | TIMESTAMP | Transaction timestamp |
Querying the Marketplace
Find Active Listings for a Pool
SELECT * FROM dob_buy_sales
WHERE token_address = 'CABC123...'
AND chain_id = '10'
AND is_active = true
ORDER BY price_per_share ASC;
Find a User's Active Listing
A user can only have one active listing per pool:
SELECT * FROM dob_buy_sales
WHERE token_address = 'CABC123...'
AND LOWER(owner_address) = LOWER('GBDM6...')
AND chain_id = '9'
AND is_active = true;
Find Purchase History for a Pool
SELECT t.*, s.owner_address AS seller_address
FROM dob_buy_sale_transactions t
JOIN dob_buy_sales s ON t.sale_address = s.sale_address
WHERE t.token_address = 'CABC123...'
ORDER BY t.created_at DESC;
Find a Listing by Unique Sale Address
SELECT * FROM dob_buy_sales
WHERE sale_address = 'SALE_a1b2c3d4e5f6...';
ID Generation
The marketplace uses a manual ID generation pattern to avoid database sequence permission issues:
// Find the current max ID
const maxIdResult = await db.dob_buy_sales.findOne({
attributes: [[db.Sequelize.fn('MAX', db.Sequelize.col('id')), 'maxId']],
raw: true
});
const nextId = (maxIdResult?.maxId || 0) + 1;
// Create with explicit ID
await db.dob_buy_sales.create({
id: nextId,
sale_address: `SALE_${crypto.randomBytes(16).toString('hex')}`,
token_address: poolAddress,
owner_address: sellerAddress,
// ... other fields
});
Smart Contract Integration
On Stellar Soroban, marketplace operations interact directly with the pool smart contract:
Listing Flow (On-Chain)
- Seller calls the marketplace contract to create a listing
- Contract records the listing parameters
- Shares are not escrowed -- ownership stays with seller until purchase
Purchase Flow (On-Chain)
- Buyer calls the marketplace contract with the listing ID and payment
- Contract verifies:
- Listing is active
- Seller still owns the shares
- Buyer has sufficient payment token balance
- Atomic swap executes:
- Shares transferred: seller --> buyer
- Payment transferred: buyer --> seller (minus commission)
- Listing updated (deactivated if fully purchased, quantity reduced if partial)
Post-Purchase Sync
After a purchase:
- Stellar sync script detects the share transfer event
pool_userstable updated:- Seller's shares decreased
- Buyer's shares increased (or new
pool_usersrecord created)
- Buyer now sees the pool in their dashboard
- Transaction recorded in
dob_buy_sale_transactions
Price Discovery
The marketplace provides organic price discovery for pool shares:
- No automated market maker -- prices are set by sellers based on their assessment of the pool's value
- Listed price is execution price -- buyers pay exactly what is listed (no slippage)
- Multiple listings -- different sellers may list at different prices, creating a natural order book
- Market signals -- listing activity and pricing trends indicate pool health and investor sentiment
Factors That Influence Share Price
| Factor | Impact on Price |
|---|---|
| Distribution yield (APR) | Higher yield tends to increase price |
| Distribution consistency | Regular distributions build confidence |
| Asset verification (TRUFA score) | Higher scores increase trust |
| Pool age and track record | Proven pools command premium |
| Remaining pool capacity | Scarcity drives price up |
| Broader market conditions | Market sentiment affects demand |
Network Support
| Network | Marketplace Available |
|---|---|
| Stellar Mainnet (10) | Yes |
| Stellar Testnet (9) | Yes |
| Ethereum Mainnet (1) | Planned |
| Base Mainnet (8453) | Planned |
| Polygon Mainnet (137) | Planned |
The marketplace is currently fully operational on Stellar networks, with EVM support planned for a future release.
API Endpoints
The marketplace is accessible through the Token Studio API:
| Endpoint | Method | Description |
|---|---|---|
/api/marketplace | GET | List all active marketplace listings |
/api/marketplace?network_id=10 | GET | Listings filtered by network |
/api/marketplace/pool/{address} | GET | Listings for a specific pool |
/api/marketplace/buy | POST | Execute a share purchase |
/api/marketplace/sell | POST | Create a new listing |
/api/marketplace/cancel | POST | Cancel an active listing |
For programmatic access, see the Agent API documentation.