On-chain credential trust for Stellar PH Bootcamp 2026
Issue, verify, and pay graduates on Stellar testnet - Soroban + Freighter, end-to-end.
| Live demo | stellaroid.tech |
| Contract (current) | CDMUOHMARNVOJZM3IVOCJUPGBHDTHFBMZCCZXEZPQDVJGILH3NIKTTW3 |
| Tx evidence | init · register · verify |
| Source verification | Fresh security-hardened testnet deploy. WASM hash 59ca403e347f4c24b1dd16fbcb65662c2837cc852946e3ae88374eed509d6f7f; Stellar Expert source re-verification pending. |
| Submission | Rise In · Stellar Smart Contract Bootcamp · Stellar PH Bootcamp 2026 |
| Result | Top 5 / 105 participants · Score: 75.00 |
The bootcamp/event submission is complete. Stellaroid Earn is now maintained as a living Stellar credential proof project.
- Roadmap:
ROADMAP.md - Maintenance checks:
MAINTENANCE.md - Custom domain cutover:
docs/STELLAROID_TECH_CUTOVER.md - Demo checklist:
docs/DEMO_CHECKLIST.md - Canonical live URL:
stellaroid.tech - Operational status route:
/status
www.stellaroid.tech and earn.stellaroid.tech redirect to the canonical apex URL.
Problem - Bootcamp certificates are PDFs that anyone can fake and no one can independently verify. Employers skip verification or pay for a background check service.
Solution - Stellaroid Earn anchors credential hashes on a Soroban smart contract where approved issuers register and verify certificates, anyone checks proof at a public URL with no login, and employers pay graduates in XLM - all on-chain.
Why Stellar - Sub-cent fees and 5-second finality make issuing credentials cheap enough to never skip. simulateTransaction lets anyone verify with zero wallet setup. Native XLM via SAC closes the loop from proof to payout on one chain.
Every credential produces a public Verified Badge URL - no wallet, no login, no API key. Green means verified on-chain. Amber means issued but not yet verified.
![]() Verified Try it yourself → |
![]() Issued (locked) Try it yourself → |
Contract on Stellar Expert: CDMUOHMA…IKTTW3
Full architecture document:
docs/ARCHITECTURE.md
sequenceDiagram
autonumber
actor Issuer as Approved Issuer
actor Student
actor Employer
participant FE as Stellaroid Earn (Next.js)
participant FR as Freighter
participant SC as Soroban contract<br/>(stellaroid_earn)
participant XLM as Stellar testnet
Issuer->>FE: Open /app, paste student wallet + cert hash
FE->>FR: requestAccess + signTransaction(register_certificate)
FR->>XLM: Submit tx
XLM->>SC: register_certificate(issuer, student, hash, title, cohort, uri)
SC-->>XLM: cert_reg event
Issuer->>FE: Click "Approve credential"
FE->>FR: signTransaction(verify_certificate)
FR->>XLM: Submit tx
XLM->>SC: verify_certificate(verifier, hash)
SC-->>XLM: cert_ver event
Student->>FE: Share /proof/<hash> (QR or link)
Note over FE,SC: Read-only get_certificate via simulateTransaction
Employer->>FE: Open /app as Employer, paste hash + amount
FE->>FR: signTransaction(link_payment)
FR->>XLM: Submit tx (XLM transfer + payment event)
Design decisions:
- soroban-sdk 22 with typed
#[contracterror]enum (17 variants), persistent + instance storage, TTL 518k/1.04M ledgers - Issuer trust layer: self-register → admin approve → issue credentials. Suspended issuers are blocked on-chain
- Two read paths: server-side RSC with
revalidate=60(CDN-cached proof pages) + client-sidesimulateTransaction(dashboard state) - One write path: Freighter signs →
sendTransaction→ poll for result - CSP locks
connect-srcto*.stellar.org- no third-party data leaks
- Rust (stable) +
wasm32v1-nonetarget - Stellar CLI v26+
- Node.js 20+ and npm
- Freighter browser extension set to Testnet
Full setup guide: setup/[ENG] Pre-Workshop Setup Guide.pdf
cd contract
cargo test # contract test suite
stellar contract build # builds wasm32v1-none target
# Deploy to testnet
stellar keys generate my-key --network testnet --fund
stellar contract deploy \
--wasm target/wasm32v1-none/release/stellaroid_earn.wasm \
--source my-key --network testnetcd frontend
cp .env.example .env.local # fill in contract ID + read address
npm install
npm run dev # http://localhost:3000Environment variables (.env.local):
NEXT_PUBLIC_STELLAR_RPC_URL=https://soroban-testnet.stellar.org
NEXT_PUBLIC_STELLAR_NETWORK=TESTNET
NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
NEXT_PUBLIC_SOROBAN_CONTRACT_ID=<your deployed contract ID>
NEXT_PUBLIC_STELLAR_ADMIN_ADDRESS=<your admin G... address>
NEXT_PUBLIC_STELLAR_READ_ADDRESS=<any funded testnet address for read-only calls>
NEXT_PUBLIC_SOROBAN_ASSET_ADDRESS=CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC
NEXT_PUBLIC_SOROBAN_ASSET_CODE=XLM
NEXT_PUBLIC_SOROBAN_ASSET_DECIMALS=7
NEXT_PUBLIC_STELLAR_EXPLORER_URL=https://stellar.expert/explorer/testnet
NEXT_PUBLIC_CANONICAL_URL=https://stellaroid.techEvery action in the demo flow is a real transaction on Stellar testnet. Click any hash to verify on Stellar Expert.
| Action | Tx Hash | Result |
|---|---|---|
init |
37afd2a5…96bb |
Contract initialized with admin + XLM token |
register_certificate |
f3d6c0f4…8c13 |
Demo credential hash registered for student |
verify_certificate |
cf734925…a0b |
Status changed to Verified |
Live certificates (testnet, contract CDMUOHMA…):
| Hash | Cohort | Status |
|---|---|---|
c02ce160…aea3 |
Stellar PH Bootcamp 2026 | Verified |
| Function | Caller | Description |
|---|---|---|
init(admin, token) |
Deployer | Initialize contract with admin address and XLM token |
register_issuer(address, name, website, category) |
Anyone | Submit issuer application (Pending status) |
approve_issuer(admin, issuer) |
Admin | Approve an issuer to register credentials |
suspend_issuer(admin, issuer) |
Admin | Suspend a misbehaving issuer |
get_issuer(issuer) |
Anyone | Read issuer record and status |
register_certificate(issuer, student, cert_hash, title, cohort, metadata_uri) |
Approved issuer | Register a credential hash for a graduate |
verify_certificate(issuer, cert_hash) |
Admin or issuer | Mark a credential Verified |
revoke_certificate(issuer, cert_hash) |
Admin or issuer | Permanently revoke a credential |
suspend_certificate(issuer, cert_hash) |
Admin or issuer | Temporarily suspend a credential |
reward_student(student, cert_hash, amount) |
Admin | Admin-initiated XLM payment to a graduate |
link_payment(employer, student, cert_hash, amount) |
Employer | Employer pays graduate in XLM, linked to credential |
get_certificate(cert_hash) |
Anyone | Read full credential record and status |
Issued --> Verified (issuer or admin calls verify_certificate)
--> Revoked (issuer or admin calls revoke_certificate)
--> Suspended (issuer or admin calls suspend_certificate)
--> Expired (reserved status; new credentials currently use expires_at = 0 unless a future issuer flow sets expiry)
Contract tests cover the trust layer, access control, revocation, opportunity escrow, milestone caps, and events:
running 12 tests
test test::t1_happy_path_with_approved_issuer ... ok
test test::t2_unapproved_issuer_cannot_issue ... ok
test test::t3_suspended_issuer_cannot_issue ... ok
test test::t4_wrong_approved_issuer_cannot_verify ... ok
test test::t5_revoked_credential_blocks_payment ... ok
test test::t6_issuer_events_emit ... ok
test result: ok. 12 passed; 0 failed; 0 ignored
| Test | What it verifies |
|---|---|
| t1 | Happy path: approved issuer registers + verifies credential, admin rewards student |
| t2 | Pending (unapproved) issuer cannot register a credential |
| t3 | Suspended issuer cannot register a credential |
| t4 | Approved issuer A cannot verify issuer B's credential |
| t5 | Revoked credential blocks downstream payments |
| t6 | Events emitted correctly for init, register_issuer, approve_issuer |
| t7-t10 | Opportunity create, fund, submit, approve, release, refund, and invalid transition behavior |
| t11 | Opportunity milestone count is capped to prevent unbounded work/rendering |
| t12 | Employer can refund after candidate submission to avoid escrow lock |
Full security checklist: docs/SECURITY.md
Covers: smart contract access control, frontend CSP/HSTS/X-Frame-Options, strict input validation, JSON-LD escaping, URL sanitization, proof-claim integrity, fee-sponsor restrictions, error normalization, SSRF prevention, and operational security.
Stellaroid Earn keeps fee bump transaction support (CAP-0015) behind a server-to-server authorization boundary. Public browser clients do not automatically send signed XDR to /api/fee-bump.
How it works:
- A trusted server obtains a user-signed transaction for an allowed Stellaroid Earn method
- The trusted server calls
/api/fee-bumpwithAuthorization: Bearer <FEE_SPONSOR_TOKEN> - The route enforces XDR size, signature, operation count, network, contract ID, method allow-list, and fee-ceiling checks
- Only then does the sponsor key wrap the transaction as a fee bump
Implementation:
- Server route:
frontend/src/app/api/fee-bump/route.ts - Client helper:
frontend/src/lib/fee-bump.ts - Config:
FEE_SPONSOR_SECRET+FEE_SPONSOR_TOKENare server-only. Public browser auto-sponsorship stays disabled; trusted server callers must provide the bearer token explicitly. - Browser fallback: normal user-paid Freighter transactions remain the default path.
- Metrics dashboard:
/metrics- on-chain stats (events, proofs, transactions, certificates, rewards, payments) refreshed every 30s - Health endpoint:
/api/health- cached JSON health check (config, RPC latency, contract availability) - Events API:
/api/events- structured contract event data for external consumers - Vercel Analytics: Web analytics integrated via
@vercel/analytics
Contract events are indexed by querying Soroban RPC's getEvents method across a 60,000-ledger window (~2 days). Events are decoded from ScVal, categorized by kind (cert_reg, cert_ver, reward, payment), and served via the /api/events REST endpoint and the /metrics dashboard. The approach is lightweight and serverless - no external indexer infrastructure required.
| Component | Version |
|---|---|
| Soroban SDK | 22.0.0 |
| Stellar CLI | 26+ |
| Next.js | 15 (App Router) |
| React | 19 |
| @stellar/stellar-sdk | latest |
| @stellar/freighter-api | latest |
| Tailwind CSS | v4 |
stellaroid-earn/
├── contract/
│ ├── src/
│ │ ├── lib.rs # Soroban credential + payment contract
│ │ └── test.rs # contract security and lifecycle tests
│ └── Cargo.toml
├── frontend/
│ ├── src/
│ │ ├── app/ # Next.js App Router pages
│ │ │ ├── app/ # Participant dashboard (issuer + employer)
│ │ │ ├── issuer/ # Issuer registration + lookup
│ │ │ └── proof/[hash]/ # Public shareable verified badge
│ │ ├── components/ # UI components (proof card, wallet, badges)
│ │ ├── hooks/ # Freighter wallet state
│ │ └── lib/ # Contract client, RPC helpers, types
│ └── .env.example
├── demo/ # Demo script, FAQ, press kit
├── scripts/ # Screenshot capture (Playwright)
├── images/ # README screenshots
├── LICENSE
└── README.md
https://github.com/user-attachments/assets/stellaroid-earn-demo.mp4
Full walkthrough: landing page → about → app dashboard (wallet connect) → issuer console → verified proof page → on-chain evidence on Stellar Expert.
Local copy: demo/stellaroid-earn-demo.mp4
Demo Day slides: /slides (integrated into the app, arrow keys to navigate)
Submission/demo checklist: docs/DEMO_CHECKLIST.md
30+ users tested the MVP on Stellar testnet. Each wallet address is verifiable on Stellar Expert. 18 wallets have direct contract interactions (register_issuer), 12 are funded explorers.
View all 30 wallet addresses
| # | Wallet Address | Verified On-Chain |
|---|---|---|
| 1 | GCBBBLZVJVVM2ZMXPNMDN2ATH7AJ2H4BHOKA7JOJT6EMWTOKCGRKUK6I |
Stellar Expert |
| 2 | GALGZBDSFG4FRTFSO7XLURBJRYC6PA34H73IF66G7BZOXXQDMWSHPXEU |
Stellar Expert |
| 3 | GAWJEP7LWY7WPLP7SBPR4MWQGQJIBAHVNVXYQE33F5FL2VFMFGBBFZ4B |
Stellar Expert |
| 4 | GCBZAJUZXRHNLVR4RCG743KSTKQSVFKXQCNYWAH4FVHDVSS5IT6DWSI3 |
Stellar Expert |
| 5 | GAQZJQPZI7YZBUN6YVAFACVKAH6ODNBO3DVELP34VW4MLLUBCL5DMMNS |
Stellar Expert |
| 6 | GAYOZX7LSYYYROU4SEBKGOOHOPUWYORPXEDHZJOXZ5Q45XZED7IMXG2U |
Stellar Expert |
| 7 | GDVNNL2QFO4PFYDLVLZTL2GKKOZR3YBV2AIIV7U44DXDOKKRJFIMLWCB |
Stellar Expert |
| 8 | GCFL24VJA3LPZLIOJ3AAVGCUGOW4A7ZUWNNEGR332IZ2MHMUWCTK3GVG |
Stellar Expert |
| 9 | GBNVAVBVELOM2FBBPWDTUBM5DRECBY2MKPZ6YYO3CNKKSFCUUSE3HAU5 |
Stellar Expert |
| 10 | GBWATJDBLCF7PPUQYBWBXCUQ5ZXRHKHZ7RAFHWZ4SLMNH45VBRPAXXYY |
Stellar Expert |
| 11 | GDBJYDYLU3JH7V6X6KHPWQOSRQNXTL7OYTD6HUNVGB2J6Y7CUUX4WW6R |
Stellar Expert |
| 12 | GA6DCDZIIP3FGLIAU5FLUZLBBFCM6XD26JDJVJCA6EL2LKY5OKA7YAQF |
Stellar Expert |
| 13 | GBTNI3CULIDVJWABRYF5T56W7COYTA5JCRD3EAKO3VDSDWCUT2ZHSLAO |
Stellar Expert |
| 14 | GD2PSTZL2YQC66C4PGFS5D64A6473IEKCZKNMIM5B7JWVLVS2N27D7QU |
Stellar Expert |
| 15 | GCZJCXZTC5KELSLQJU6QUIDMRZ2HFTUIDYL3PCOKGR7XRAFI373DO6PU |
Stellar Expert |
| 16 | GCD4WRBPCKIPMDKLQA2LRAGYOIWCVRXJI4XNW4TI2ECVNKQO3T2XUSHG |
Stellar Expert |
| 17 | GBJXD5H457AKCFEGTSKYMD4MRSBBMGTUCOKEBU6YQ7TKNZ7SY2W37KKY |
Stellar Expert |
| 18 | GAGR7D5K4VL5HNOZCL6CYZIGT5FNYZW7I5WXGX6HSBZLLVQ3NG77XBAO |
Stellar Expert |
| 19 | GAZXPBADNPTKWAGUWZM6KWEMIO4MQVU4GW3ZJXKHEO4BOBL5SLERSQYR |
Stellar Expert |
| 20 | GDANCIDPUHS4IQUNHRM5RNKVOXTRR5RKIYYEE7HVPB2RWD76J66CS2DH |
Stellar Expert |
| 21 | GCHZOQCDMG5J6NC2MNAR6EH5JFGI6JEP7TQWWUDRWER75Q3W3NC52HMG |
Stellar Expert |
| 22 | GC54CLYWNJ2AQZCAA2LVXOR2XTNGGCZYDSEJLLQBV6D4EDXN6D6DFGPX |
Stellar Expert |
| 23 | GDTJBRZXXMOWPF3LPMM7V4WOBIPLGR6BXTRDBYH6VCBRBL5Y76NK5JHY |
Stellar Expert |
| 24 | GDK5LNJFLU5LLNQDDZJ4SUPXASK7SULASCAGEHF5IT65FX2FYZ56CHAM |
Stellar Expert |
| 25 | GBTY2BMYVRP2SFSFJXMHFQ6XQOKUS5JEZEAF3ZI5356FK7EQN56G57QE |
Stellar Expert |
| 26 | GANDLIFPFLNRYMIK6PG3BQU437PVUDLKS2VBCBYAMCJOKYZPRJWGORSU |
Stellar Expert |
| 27 | GAVCDYPJLPA2W4EYIMDXPSGAMUJDDOCSGNVZAX7UER4B4AKLVSDZSEIT |
Stellar Expert |
| 28 | GARXSQZMDE4YF5IL6TWDAF4IAQG326JWAMOB5MAVAM3BOTXKM47Q6AQC |
Stellar Expert |
| 29 | GBS6ERMNCYSO2EK7VPAGJP6TI6IEKGRJNUTKZWJ7KDBLY7Y6MG3CFEWF |
Stellar Expert |
| 30 | GCOON62FGOWAW44SAWI3UKNJY52W7RD4CIBEQFZJEI2J56MWOCKUENAC |
Stellar Expert |
- Google Form: Stellaroid Earn - User Feedback Form
- Exported responses:
docs/user-feedback-responses.csv - Full feedback documentation:
docs/USER_FEEDBACK.md
After collecting feedback from testnet users, the following iteration was completed:
| Feedback | Improvement | Commit |
|---|---|---|
| Users confused about which role (Issuer vs Employer) to pick after connecting wallet | Added contextual role guidance hints below the persona toggle | c1450bf |
Mark Siazon - Hybrid Product Designer & Full-Stack Developer
- Rise In - Stellar Smart Contract Bootcamp
- Stellar Philippines - Stellar PH Bootcamp 2026
- Workflow PH - Community partner
- Stellar Docs · Soroban SDK · Freighter · Stellar Expert
MIT License - see LICENSE for details.







