Blockplot Protocol Docs
Complete reference for the Blockplot Soroban permissioned RWA tokenization protocol — smart contracts, API, user flows, and wallet integration.
Overview
Blockplot Soroban is a compliant Real World Asset (RWA) tokenization platform that enables users globally to invest in fractionalized, yield-bearing assets such as real estate, infrastructure, and treasury-backed instruments.
The platform uses Soroban smart contracts on the Stellar network to tokenize off-chain assets into transferable digital ownership units while enforcing compliance, identity verification, governance rules, and reward distribution entirely on-chain.
Blockplot lowers the entry barrier to global asset ownership by enabling investments from as little as $1, while providing liquidity, transparent reward distribution, and decentralized governance.
Problem Statement
Traditional real-world asset investing suffers from structural barriers that exclude the majority of the world:
Blockplot solves these challenges through compliant fractional ownership infrastructure built on Stellar — where transactions settle in seconds for fractions of a cent.
Architecture
Blockplot is composed of three layers: on-chain contracts, an off-chain API, and the user-facing web application.
┌─────────────────────────────────────────────────────────┐
│ blockplot-frontend │
│ Next.js · Tailwind · Freighter SDK │
└───────────────────────┬─────────────────────────────────┘
│ REST
┌───────────────────────▼─────────────────────────────────┐
│ blockplot-backend │
│ NestJS · Identity · Assets · Yield modules │
└───────────────────────┬─────────────────────────────────┘
│ Soroban RPC
┌───────────────────────▼─────────────────────────────────┐
│ blockplot-contracts │
│ │
│ BlockplotID ──► FractionalAsset ──► PublicSale │
│ │ │
│ YieldDistributor │
│ │
│ Stellar · Soroban Runtime │
└─────────────────────────────────────────────────────────┘Contract Interaction Flow
User wallet
│
├─ 1. identity check → BlockplotID.is_verified()
│
├─ 2. purchase → PublicSale.purchase()
│ │
│ FractionalAsset.mint()
│
└─ 3. claim yield → YieldDistributor.claim()Smart Contracts
All contracts are written in Rust targeting the Soroban WASM runtime. The workspace lives at github.com/Stellar-Land/blockplot-contracts.
cargo build --target wasm32-unknown-unknown --releaseBlockplotID
The identity and compliance layer. Every wallet that interacts with the protocol must first be verified through this contract. An admin (the compliance provider) controls status transitions.
| Function | Access | Description |
|---|---|---|
| initialize(admin) | Once | Sets the compliance admin |
| set_status(user, status) | Admin | Sets identity state for a wallet |
| get_status(user) | Public | Returns current IdentityStatus |
| is_verified(user) | Public | Returns true if status is Verified |
Identity States
None ──► Pending ──► Verified
│
RevokedUsage
// Approve a user on testnet stellar contract invoke \ --id <BLOCKPLOT_ID_CONTRACT> \ --source admin \ --network testnet \ -- set_status \ --user GABC...XYZ \ --status Verified
FractionalAsset
An ownership token contract representing fractional exposure to an off-chain asset. Each deployed instance corresponds to one real-world asset. A per-wallet owner_cap prevents concentration and enforces ownership limits.
| Function | Access | Description |
|---|---|---|
| initialize(admin, name, total_supply, owner_cap) | Once | Deploys and configures the asset token |
| mint(to, amount) | Admin | Issues tokens, enforces cap |
| transfer(from, to, amount) | Holder | Transfers tokens, cap-checked on recipient |
| balance_of(account) | Public | Returns token balance for a wallet |
| total_supply() | Public | Returns total issued supply |
| owner_cap() | Public | Returns max tokens any wallet may hold |
BlockplotID.is_verified() before constructing a transfer transaction.PublicSale
The primary issuance marketplace. An admin opens and closes sale phases, sets the token price, and the contract tracks total funds raised. It returns the number of tokens to issue — token minting is handled by a subsequent FractionalAsset.mint() call.
| Function | Access | Description |
|---|---|---|
| initialize(admin, token_price) | Once | Sets admin and per-token price in stroops |
| set_active(active) | Admin | Opens (true) or closes (false) the sale |
| purchase(buyer, payment_amount) | Verified buyer | Records purchase, returns token count |
| total_raised() | Public | Cumulative funds raised |
| is_active() | Public | Whether the sale is currently open |
| token_price() | Public | Current price per token |
Purchase flow
// 1. Check identity
const verified = await contract.is_verified(walletAddress)
if (!verified) throw new Error("KYC required")
// 2. Call purchase — returns token count
const tokens = await publicSale.purchase(buyer, paymentAmount)
// 3. Mint the tokens to the buyer
await fractionalAsset.mint(buyer, tokens)YieldDistributor
Collects asset-generated income (rent, treasury yield, revenue sharing) and distributes it proportionally to token holders. Allocation is expressed in basis points (bps) where 10,000 bps = 100%.
| Function | Access | Description |
|---|---|---|
| initialize(admin) | Once | Sets the distribution admin |
| deposit(caller, amount) | Admin | Deposits yield into the pool |
| allocate(holder, allocation_bps) | Admin | Credits yield share to a holder |
| claimable(holder) | Public | Returns unclaimed yield for a wallet |
| claim(holder) | Holder | Withdraws all claimable yield, returns amount |
| total_deposited() | Public | Total yield deposited to date |
Allocation formula
claimable = (total_deposited × allocation_bps) / 10_000 // Example: holder owns 5% of the asset (500 bps) // Total deposited: $10,000 // Claimable: (10_000 × 500) / 10_000 = $500
total_supply. The backend computes this off-chain after indexing balance_of values.User Flows
1 — Onboarding
User connects Freighter wallet
│
▼
User submits KYC form (name, country, ID)
│
▼
Backend stores submission, status = "pending"
│
▼
Compliance admin reviews and calls set_status(..., Verified)
│
▼
User gains protocol access — can purchase asset tokens2 — Investing in an Asset
User browses asset catalog → selects an asset
│
▼
Protocol checks: BlockplotID.is_verified(user) ✓
PublicSale.is_active() ✓
payment ≥ token_price ✓
│
▼
PublicSale.purchase(buyer, amount) → returns token_count
│
▼
FractionalAsset.mint(buyer, token_count)
│
▼
Tokens appear in user's portfolio3 — Claiming Yield
Asset generates income (rent collected, yield received)
│
▼
Admin calls YieldDistributor.deposit(caller, income_amount)
│
▼
Backend indexes balance_of for all holders
Computes each holder's allocation_bps
│
▼
Admin calls YieldDistributor.allocate(holder, bps) for each holder
│
▼
User opens /claim dashboard
User calls YieldDistributor.claim(wallet) via Freighter
│
▼
Rewards land in user's Stellar walletAPI Reference
The backend exposes a REST API at http://localhost:3000 in development. All endpoints return JSON.
Identity — /identity
| Method | Endpoint | Description |
|---|---|---|
| POST | /identity/submit | Submit KYC data for a wallet address |
| GET | /identity/:walletAddress | Get current identity status |
| PATCH | /identity/:walletAddress/approve | Approve and verify a wallet (admin) |
| PATCH | /identity/:walletAddress/revoke | Revoke a wallet's verified status (admin) |
// Submit KYC
POST /identity/submit
{
"walletAddress": "GABC...XYZ",
"kycData": { "name": "Alice", "country": "NG" }
}
// Response
{ "walletAddress": "GABC...XYZ", "status": "pending", "updatedAt": "..." }
// Approve (admin)
PATCH /identity/GABC...XYZ/approve
// → { "status": "verified", "updatedAt": "..." }Assets — /assets
| Method | Endpoint | Description |
|---|---|---|
| POST | /assets | Register a new tokenized asset |
| GET | /assets | List all registered assets |
| GET | /assets/:id | Get a single asset by ID |
// Create asset
POST /assets
{
"name": "Lagos Commercial Tower A",
"totalSupply": 1000000,
"ownerCap": 100000,
"priceUsd": 1
}
// Response
{
"id": "uuid-here",
"name": "Lagos Commercial Tower A",
"totalSupply": 1000000,
"ownerCap": 100000,
"priceUsd": 1,
"createdAt": "..."
}Yield — /yield
| Method | Endpoint | Description |
|---|---|---|
| POST | /yield/:assetId/deposit | Deposit yield into an asset's pool |
| GET | /yield/:assetId/claimable/:walletAddress | Get claimable amount for a holder |
| POST | /yield/:assetId/claim/:walletAddress | Claim all yield for a holder |
// Deposit yield
POST /yield/asset-id-123/deposit
{ "amount": 5000 }
// Check claimable
GET /yield/asset-id-123/claimable/GABC...XYZ
// → { "walletAddress": "GABC...XYZ", "claimable": 250 }
// Claim
POST /yield/asset-id-123/claim/GABC...XYZ
// → { "walletAddress": "GABC...XYZ", "claimed": 250 }Wallet Integration
Blockplot uses Freighter — the official Stellar browser extension wallet. Install it from freighter.app before connecting.
Connecting a wallet
import { isConnected, requestAccess, getAddress } from "@stellar/freighter-api"
// Check if Freighter is installed
const { isConnected: installed } = await isConnected()
// Request access — opens the Freighter popup
const { address, error } = await requestAccess()
if (error) throw new Error(error)
console.log("Connected:", address)
// → "GABC...XYZ"Checking an existing session
// Silently restore a previous connection (no popup)
const { address } = await getAddress()
if (address) console.log("Already connected:", address)Signing a transaction
import { signTransaction } from "@stellar/freighter-api"
import { Transaction } from "@stellar/stellar-sdk"
const { signedTxXdr, error } = await signTransaction(unsignedXDR, {
networkPassphrase: Networks.TESTNET,
})
if (error) throw new Error(error)
// Submit the signed XDR to Stellar
await server.submitTransaction(TransactionBuilder.fromXDR(signedTxXdr, Networks.TESTNET))WalletProvider context in lib/wallet-context.tsx. Use the useWallet() hook in any client component to access address, connect(), and disconnect().Supported wallets
| Wallet | Status | Notes |
|---|---|---|
| Freighter | ✓ Supported | Primary integration |
| Albedo | Planned | Phase 2 |
| WalletConnect | Planned | Phase 3 — mobile support |
| Rabet | Planned | Phase 2 |
Roadmap
Phase 1 — MVP (Current)
Phase 2 — Expansion
Phase 3 — Advanced RWA Infrastructure
Ready to start building on Blockplot?