📌 Getting Started? Start with the root README for an overview. This document provides comprehensive API documentation and usage examples.
A Soroban smart contract for decentralized project registry, reviews, and verification on the Stellar network.
- Rust 1.74.0+
- Soroban CLI
- wasm32-unknown-unknown target
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add WASM target
rustup target add wasm32-unknown-unknown
# Install Soroban CLI
cargo install --locked soroban-cli --features optmake build
# or
cargo build --target wasm32-unknown-unknown --releasemake test
# or
cargo testRun a specific test:
cargo test test_register_project_successRun tests with output:
make test-verbose
# or
cargo test -- --nocaptureWe provide convenient scripts under the scripts/ directory to simplify building, deploying, initializing, and invoking the contract on Stellar networks.
Before running the scripts, configure the following environment variables. You can set them in your terminal shell or create a .env file in the root of the repository:
| Variable | Description | Default Value |
|---|---|---|
DEPLOYER_IDENTITY |
Required. The Soroban key identity used to sign transactions (e.g., alice). |
None |
NETWORK |
The Stellar network to target (testnet, mainnet, or local). |
testnet |
RPC_URL |
RPC endpoint URL for network communication. | SDF Testnet RPC URL |
PASSPHRASE |
Passphrase of the targeted Stellar network. | SDF Testnet Passphrase |
CONTRACT_ID |
The ID of the deployed contract. Automatically read from .contract_id if omitted. |
None |
ADMIN_ADDRESS |
Address of the initial admin during contract initialization. | Deployer identity address |
Builds, optimizes, and deploys the contract to the configured network:
# Export the deployer identity (or add to a .env file in the root)
export DEPLOYER_IDENTITY=alice
# Execute deployment
./scripts/deploy_testnet.shThis script automatically saves the deployed contract ID to .contract_id in the project root.
Initializes the newly deployed contract with an admin:
./scripts/initialize.shUse the invocation helper script for common functions:
# Register a project
./scripts/invoke.sh register <owner_address> "My Project" "my-project" "Project description" "DeFi"
# Fetch project details by ID
./scripts/invoke.sh get_project 1
# Fetch project details by Slug
./scripts/invoke.sh get_project_by_slug "my-project"
# Multi-sig governance (see Admin Management below)
./scripts/invoke.sh create_proposal add_admin <new_admin_address>
./scripts/invoke.sh approve_proposal <proposal_id>
./scripts/invoke.sh execute_proposal <proposal_id>
./scripts/invoke.sh get_proposal <proposal_id>Important
After deploying, you must document the deployment in the project-wide deployment manifest. Please refer to the root Deployment Documentation for details on how to update deployments.json.
All examples use the Soroban CLI. Replace <CONTRACT_ID> with your deployed contract address and alice with your configured identity.
Must be called once after deployment to set the initial admin.
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- initialize \
--admin <ADMIN_ADDRESS>Expected error if already initialized:
Error: HostError: Value already exists
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- register_project \
--params '{
"owner": "<OWNER_ADDRESS>",
"name": "My DApp",
"description": "A decentralized application on Stellar",
"category": "DeFi",
"website": "https://mydapp.example.com",
"logo_cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
"metadata_cid": null
}'Returns the new project ID (e.g., 1).
Common errors:
| Error | Cause |
|---|---|
ProjectAlreadyExists |
A project with the same name is already registered |
InvalidProjectName |
Name is empty or whitespace only |
ProjectNameTooLong |
Name exceeds the maximum allowed length |
InvalidProjectDescription |
Description is empty or whitespace only |
ProjectDescriptionTooLong |
Description exceeds the maximum allowed length |
InvalidProjectCategory |
Category is empty or whitespace only |
InvalidProjectWebsite |
Website URL format is invalid |
MaxProjectsExceeded |
Global project limit has been reached |
Only the project owner can update. All fields are optional — only provided fields are changed.
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- update_project \
--params '{
"project_id": 1,
"caller": "<OWNER_ADDRESS>",
"name": "My DApp v2",
"description": "Updated description",
"category": null,
"website": null,
"logo_cid": null,
"metadata_cid": null
}'Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
Unauthorized |
Caller is not the project owner |
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project \
--project_id 1Returns null if the project does not exist.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_projects \
--start_id 1 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_projects_by_owner \
--owner <OWNER_ADDRESS># Step 1: Initiate transfer (current owner)
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- initiate_transfer \
--project_id 1 \
--caller <CURRENT_OWNER_ADDRESS> \
--new_owner <NEW_OWNER_ADDRESS>
# Step 2: Accept transfer (new owner)
soroban contract invoke \
--id <CONTRACT_ID> \
--source new_owner_identity \
--network testnet \
-- accept_transfer \
--project_id 1 \
--caller <NEW_OWNER_ADDRESS>
# Cancel a pending transfer (current owner)
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- cancel_transfer \
--project_id 1 \
--caller <CURRENT_OWNER_ADDRESS>Common errors:
| Error | Cause |
|---|---|
TransferNotFound |
No pending transfer exists for this project |
NotPendingTransferRecipient |
Caller is not the designated new owner |
Unauthorized |
Caller is not the current owner |
soroban contract invoke \
--id <CONTRACT_ID> \
--source reviewer_identity \
--network testnet \
-- submit_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--rating 5 \
--review_cid "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"rating must be between 1 and 5. review_cid is an IPFS CID pointing to the review content.
Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
InvalidRating |
Rating is not between 1 and 5 |
DuplicateReview |
Reviewer has already submitted a review for this project |
soroban contract invoke \
--id <CONTRACT_ID> \
--source reviewer_identity \
--network testnet \
-- add_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--rating 4 \
--comment_cid '"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"'soroban contract invoke \
--id <CONTRACT_ID> \
--source reviewer_identity \
--network testnet \
-- update_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--rating 3 \
--comment_cid nullCommon errors:
| Error | Cause |
|---|---|
ReviewNotFound |
No review exists for this project/reviewer pair |
NotReviewOwner |
Caller is not the original reviewer |
soroban contract invoke \
--id <CONTRACT_ID> \
--source reviewer_identity \
--network testnet \
-- delete_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- respond_to_review \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--reviewer <REVIEWER_ADDRESS> \
--response "Thank you for your feedback!"soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_stats \
--project_id 1Returns { rating_sum, review_count, average_rating }.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- set_fee \
--admin <ADMIN_ADDRESS> \
--token '"<TOKEN_CONTRACT_ADDRESS>"' \
--verification_fee 1000000 \
--registration_fee 500000 \
--treasury <TREASURY_ADDRESS>Set --token to null to use the native XLM token.
Common errors:
| Error | Cause |
|---|---|
AdminOnly |
Caller is not an admin |
Must be called before requesting verification if a fee is configured.
soroban contract invoke \
--id <CONTRACT_ID> \
--source payer_identity \
--network testnet \
-- pay_fee \
--payer <PAYER_ADDRESS> \
--project_id 1 \
--token '"<TOKEN_CONTRACT_ADDRESS>"'Common errors:
| Error | Cause |
|---|---|
FeeConfigNotSet |
No fee configuration has been set |
TreasuryNotSet |
Treasury address is not configured |
InsufficientFee |
Transferred amount is less than the required fee |
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_fee_configThe project owner submits evidence for admin review. If a verification fee is configured, pay_fee must be called first.
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- request_verification \
--project_id 1 \
--requester <OWNER_ADDRESS> \
--evidence_cid "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
Unauthorized |
Caller is not the project owner |
InvalidStatusTransition |
Project is already pending or verified |
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- approve_verification \
--project_id 1 \
--admin <ADMIN_ADDRESS>Common errors:
| Error | Cause |
|---|---|
AdminOnly |
Caller is not an admin |
VerificationNotFound |
No verification request exists for this project |
InvalidStatusTransition |
Verification is not in Pending state |
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- reject_verification \
--project_id 1 \
--admin <ADMIN_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- revoke_verification \
--project_id 1 \
--admin <ADMIN_ADDRESS> \
--reason "Violated terms of service"Common errors:
| Error | Cause |
|---|---|
VerificationNotRevocable |
Project is not currently in Verified state |
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_verification \
--project_id 1Returns a VerificationRecord with status Unverified, Pending, Verified, or Rejected.
Common errors:
| Error | Cause |
|---|---|
VerificationNotFound |
No verification record exists for this project |
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- add_admin \
--caller <EXISTING_ADMIN_ADDRESS> \
--new_admin <NEW_ADMIN_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- remove_admin \
--caller <EXISTING_ADMIN_ADDRESS> \
--admin_to_remove <ADMIN_ADDRESS_TO_REMOVE>Common errors:
| Error | Cause |
|---|---|
CannotRemoveLastAdmin |
Removing this admin would leave the contract with no admins |
AdminNotFound |
The address to remove is not an admin |
Unauthorized |
Caller is not an admin, or get_admin_approval_threshold() > 1 (use the proposal workflow) |
When the approval threshold is greater than 1, add_admin, remove_admin, and further threshold changes cannot be called directly. Use scripts/invoke.sh with a different DEPLOYER_IDENTITY for each admin.
Step 1 — Raise the threshold (still allowed while threshold is 1):
export NETWORK=testnet
export CONTRACT_ID=<CONTRACT_ID>
export DEPLOYER_IDENTITY=alice
./scripts/invoke.sh add_admin "$(soroban keys address bob)"
./scripts/invoke.sh add_admin "$(soroban keys address carol)"
./scripts/invoke.sh set_admin_approval_threshold 2Step 2 — Create a proposal (create_proposal). The proposer is recorded as the first approval. Returns proposal_id.
export DEPLOYER_IDENTITY=alice
./scripts/invoke.sh create_proposal add_admin "$(soroban keys address dave)"
./scripts/invoke.sh get_proposal 1Equivalent raw invoke:
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- create_proposal \
--proposer <ALICE_ADDRESS> \
--payload '{"AddAdmin":"<DAVE_ADDRESS>"}'Supported helper payloads: add_admin, remove_admin, set_threshold, set_fee, approve_verification, reject_verification, revoke_verification.
Step 3 — Approve (approve_proposal) with a different admin until the threshold is met. Duplicate approval by the same admin fails.
export DEPLOYER_IDENTITY=bob
./scripts/invoke.sh approve_proposal 1soroban contract invoke \
--id <CONTRACT_ID> \
--source bob \
--network testnet \
-- approve_proposal \
--admin <BOB_ADDRESS> \
--proposal_id 1Step 4 — Execute (execute_proposal) once status is Approved. This applies the payload and sets status to Executed.
export DEPLOYER_IDENTITY=carol
./scripts/invoke.sh execute_proposal 1
./scripts/invoke.sh is_admin "$(soroban keys address dave)"soroban contract invoke \
--id <CONTRACT_ID> \
--source carol \
--network testnet \
-- execute_proposal \
--caller <CAROL_ADDRESS> \
--proposal_id 1If the threshold is 1, skip step 3: creating the proposal already satisfies the threshold, so any admin can execute_proposal immediately.
A full deploy-then-govern walkthrough lives in the root Deployment Documentation.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- is_admin \
--address <ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_verification_history \
--project_id 1Returns a vector of all verification records for the project, including historical status changes.
When a verified project's verification is expiring, the owner can request renewal.
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- request_renewal \
--project_id 1 \
--requester <OWNER_ADDRESS> \
--evidence_cid "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
Unauthorized |
Caller is not the project owner |
InvalidStatusTransition |
Project is not currently verified |
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- approve_renewal \
--project_id 1 \
--admin <ADMIN_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- reject_renewal \
--project_id 1 \
--admin <ADMIN_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_renewal_request \
--project_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_renewal_history \
--project_id 1 \
--start_index 0 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- is_verification_expired \
--project_id 1Returns true if the verification has expired, false otherwise.
Set the minimum age (in seconds) a project must exist before it can be verified.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- set_min_project_age \
--admin <ADMIN_ADDRESS> \
--min_age_seconds 86400soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_min_project_ageSet how long (in seconds) a verification remains valid before renewal is required.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- set_verification_duration \
--admin <ADMIN_ADDRESS> \
--duration_seconds 2592000soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_verification_durationLink two related projects together (e.g., main project and its mobile app).
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- link_project \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--linked_project_id 2Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
One or both projects do not exist |
Unauthorized |
Caller is not the owner of the project |
AlreadyLinked |
Projects are already linked |
CannotLinkToSelf |
Cannot link a project to itself |
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- unlink_project \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--linked_project_id 2soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_linked_projects \
--project_id 1Returns a vector of linked project IDs.
Mark a project as featured or remove featured status.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- set_featured \
--admin <ADMIN_ADDRESS> \
--project_id 1 \
--featured truesoroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_featured_projects \
--start 0 \
--limit 10Report a project for spam, scams, broken links, or abusive metadata.
soroban contract invoke \
--id <CONTRACT_ID> \
--source reporter_identity \
--network testnet \
-- report_project \
--project_id 1 \
--reporter <REPORTER_ADDRESS> \
--reason_cid "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
AlreadyReported |
User has already reported this project |
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_reports \
--project_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_report_count \
--project_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- has_user_reported \
--project_id 1 \
--reporter <REPORTER_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- clear_project_reports \
--project_id 1 \
--admin <ADMIN_ADDRESS>Report a review for moderation.
soroban contract invoke \
--id <CONTRACT_ID> \
--source reporter_identity \
--network testnet \
-- report_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--reporter <REPORTER_ADDRESS>Common errors:
| Error | Cause |
|---|---|
ReviewNotFound |
No review exists for this project/reviewer pair |
ReviewAlreadyReported |
This review has already been reported |
Hide a reported review from public view.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- hide_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--admin <ADMIN_ADDRESS>Common errors:
| Error | Cause |
|---|---|
ReviewAlreadyHidden |
Review is already hidden |
Restore a previously hidden review.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- restore_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--admin <ADMIN_ADDRESS>Common errors:
| Error | Cause |
|---|---|
ReviewNotHidden |
Review is not currently hidden |
Permanently delete a review (hard delete).
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- admin_delete_review \
--project_id 1 \
--reviewer <REVIEWER_ADDRESS> \
--admin <ADMIN_ADDRESS>Enable or disable reviews for a project.
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- set_reviews_enabled \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--enabled falseCommon errors:
| Error | Cause |
|---|---|
ReviewsDisabled |
Reviews are disabled for this project |
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_reviews_enabled \
--project_id 1Archive a project (owner only). Archived projects are not listed in general queries.
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- archive_project \
--project_id 1 \
--caller <OWNER_ADDRESS>Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
Unauthorized |
Caller is not the project owner |
AlreadyArchived |
Project is already archived |
Reactivate an archived project (owner only).
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- reactivate_project \
--project_id 1 \
--caller <OWNER_ADDRESS>Common errors:
| Error | Cause |
|---|---|
ProjectNotArchived |
Project is not currently archived |
Create a new curated collection of projects.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- create_collection \
--admin <ADMIN_ADDRESS> \
--name "DeFi Projects" \
--description "Curated list of DeFi applications"Returns the new collection ID.
Common errors:
| Error | Cause |
|---|---|
CollectionExists |
A collection with this name already exists |
Update a collection's name and description.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- update_collection \
--admin <ADMIN_ADDRESS> \
--collection_id 1 \
--name "Updated Collection Name" \
--description "Updated description"Common errors:
| Error | Cause |
|---|---|
CollectionNotFound |
No collection exists with the given ID |
Delete a collection and its project associations.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- delete_collection \
--admin <ADMIN_ADDRESS> \
--collection_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- add_project_to_collection \
--admin <ADMIN_ADDRESS> \
--collection_id 1 \
--project_id 1Common errors:
| Error | Cause |
|---|---|
AlreadyInCollection |
Project is already in this collection |
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- remove_project_from_collection \
--admin <ADMIN_ADDRESS> \
--collection_id 1 \
--project_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_collection \
--collection_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_collections \
--start 0 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_collection_projects \
--collection_id 1 \
--start 0 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_collection_project_count \
--collection_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_collection_countsoroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_admin_action_log_entry \
--log_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_admin_actions \
--start 0 \
--limit 10Returns admin action log entries with pagination (most recent first).
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_admin_action_log_countMark a project as claimable by others (owner only).
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- set_project_claimable \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--claimable trueSubmit a request to claim ownership of a claimable project.
soroban contract invoke \
--id <CONTRACT_ID> \
--source claimant_identity \
--network testnet \
-- submit_claim_request \
--project_id 1 \
--claimant <CLAIMANT_ADDRESS> \
--proof_cid "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"Returns the claim request ID.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- approve_claim_request \
--claim_request_id 1 \
--admin <ADMIN_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- reject_claim_request \
--claim_request_id 1 \
--admin <ADMIN_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_claim_request \
--claim_request_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_claim_requests_for_project \
--project_id 1Add a dependency to a project (owner only).
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- add_project_dependency \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--dependency '{
"name": "Stellar SDK",
"version": "2.0.0",
"type": "library",
"url": "https://github.com/stellar/js-stellar-sdk"
}'Common errors:
| Error | Cause |
|---|---|
ProjectNotFound |
No project exists with the given ID |
Unauthorized |
Caller is not the project owner |
Update an existing dependency (owner only).
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- update_project_dependency \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--dependency_key '{
"name": "Stellar SDK",
"version": "2.0.0"
}' \
--new_dependency '{
"name": "Stellar SDK",
"version": "2.1.0",
"type": "library",
"url": "https://github.com/stellar/js-stellar-sdk"
}'Remove a dependency from a project (owner only).
soroban contract invoke \
--id <CONTRACT_ID> \
--source alice \
--network testnet \
-- remove_project_dependency \
--project_id 1 \
--caller <OWNER_ADDRESS> \
--dependency_key '{
"name": "Stellar SDK",
"version": "2.0.0"
}'soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_dependencies \
--project_id 1Report a project as a duplicate of another project.
soroban contract invoke \
--id <CONTRACT_ID> \
--source reporter_identity \
--network testnet \
-- open_duplicate_dispute \
--project_id 2 \
--original_project_id 1 \
--creator <REPORTER_ADDRESS> \
--evidence_cid "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"Returns the dispute ID.
Resolve a duplicate dispute with an action (keep_original, keep_duplicate, or merge).
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- resolve_duplicate_dispute \
--dispute_id 1 \
--admin <ADMIN_ADDRESS> \
--action "KeepOriginal"soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_duplicate_dispute \
--dispute_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_disputes_for_project \
--project_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_projects_by_status \
--status "Verified" \
--start_id 1 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_projects_by_category \
--category "DeFi" \
--start_index 0 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- list_projects_by_tag \
--tag "nft" \
--start_index 0 \
--limit 10soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_projects_by_ids \
--ids '[1, 2, 3]'soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_by_slug \
--slug "my-dapp"Get statistics for multiple projects in a single call.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_stats_batch \
--ids '[1, 2, 3]'Get verification records for multiple projects in a single call.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_verifications_batch \
--ids '[1, 2, 3]'Get multiple reviews in a single call.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_reviews_by_ids \
--ids '[(1, "<REVIEWER_ADDRESS1>"), (2, "<REVIEWER_ADDRESS2>")]'Get all review CIDs for a project.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_review_cids \
--project_id 1soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_owner_project_count \
--owner <OWNER_ADDRESS>soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_project_countsoroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_admin_countsoroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_configReturns a stable configuration snapshot for frontends and indexers, including
fee settings, treasury, admin count, pause state, version, and public limits.
paused is currently false because the contract does not yet include a pause
feature.
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
-- get_admin_listPrune verification history, keeping only the most recent keep_count records.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- clear_verification_history \
--project_id 1 \
--admin <ADMIN_ADDRESS> \
--keep_count 5Returns the number of records removed.
Clear all renewal history records for a project.
soroban contract invoke \
--id <CONTRACT_ID> \
--source admin_identity \
--network testnet \
-- clear_renewal_history \
--project_id 1 \
--admin <ADMIN_ADDRESS>Returns the number of records removed.
- Project Registry: Register and manage project metadata on-chain
- Review System: Submit and manage project reviews with ratings and moderation
- Verification: Request, approve, and renew project verification
- Fee Management: Configurable fees for operations
- Access Control: Owner-based permissions and admin management
- TTL Management: Automatic and manual Time-To-Live extension for persistent storage
- Project Linking: Link related projects together
- Featured Projects: Admin-curated featured project lists
- Project Reporting: Report projects for spam, scams, or abuse
- Collections: Admin-curated collections of projects
- Project Claiming: Claim ownership of unowned projects
- Dependencies: Track project dependencies
- Duplicate Disputes: Report and resolve duplicate projects
The contract implements comprehensive TTL management for Soroban persistent storage to ensure data doesn't expire unexpectedly.
- Critical Data (admin, fees, treasury): 30 days
- Project Data: 90 days
- Review Data: 60 days
- Verification Data: 45 days
- User Data: 60 days
# Extend TTL for a specific project
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_project_ttl --project_id 1
# Extend TTL for many projects; missing project IDs are skipped
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_projects_ttl --project_ids '[1,2,3]'
# Extend TTL for critical configuration
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_critical_config_ttl
# Extend TTL for user data
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_user_ttl --user <USER_ADDRESS>
# Extend TTL for a review
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_review_ttl --project_id 1 --reviewer <REVIEWER_ADDRESS>
# Extend TTL for many reviews; missing reviews are skipped
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_reviews_ttl --review_ids '[[1,"<REVIEWER_ADDRESS>"],[2,"<REVIEWER_ADDRESS>"]]'
# Extend TTL for verification data
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- extend_verification_ttl --project_id 1Batch TTL calls accept up to 100 records and return the number of existing records refreshed.
make help # Show all commands
make build # Build contract
make test # Run tests
make test-verbose # Run tests with output
make fmt # Format code
make lint # Run linter
make clean # Clean artifacts
make dev # Run full dev workflow (fmt + lint + test + build)
make ci # Run CI checks (check + lint + test)cargo build --target wasm32-unknown-unknown --release
cargo test
cargo fmt
cargo clippy
cargo cleansrc/
├── lib.rs # Main contract interface
├── constants.rs # Constants, limits, and TTL thresholds
├── errors.rs # Error definitions
├── events.rs # Event emissions
├── fee_manager.rs # Fee handling
├── project_registry.rs # Project management
├── review_registry.rs # Review system
├── verification_registry.rs # Verification logic
├── rating_calculator.rs # Rating calculations
├── storage_keys.rs # Storage keys
├── storage_manager.rs # TTL management
├── types.rs # Data structures
└── tests/ # Tests
- Event Reference: EVENTS_SCHEMA.md defines topics, payload structures, and compatibility patterns for all emitted contract events.
- Threat Model: THREAT_MODEL.md documents trust boundaries, admin capabilities, mitigation steps, and unresolved risks.
- Review CID Schema: review-cid.schema.json defines the off-chain JSON schema expected for review content CIDs.
- Review Example: review-cid.example.json provides a valid off-chain review document matching the schema.
Contributions are welcome! Please open an issue or pull request.