- Contributing Guide - Learn how to contribute to the project
- Code of Conduct - Guidelines for community interactions
- Maintainers - Project maintainers and areas of ownership
- Changelog - Release notes and version history
- Security Policy - Security guidelines and vulnerability reporting
Decision: Option B (conservative) β keep campaign/ (milestonex-campaign) as the canonical crowdfunding contract for all new development, audits, deployments, and integrations. The campaign/ implementation remains the authoritative contract for milestone flows, refunds, freeze/upgrade controls, reentrancy protection, typed errors, and dashboard analytics.
crates/contracts/core/ (milestonex-core) is retained only as a legacy compatibility/reference contract. Do not add new campaign features there; use campaign/ for any new logic, analytics endpoints, or deployment work. Any remaining behavior worth preserving from core should be migrated into campaign/ before core is removed in a future breaking release.
Canonical campaign analytics now live on milestonex-campaign: use get_campaign_report, get_platform_summary, get_dashboard_metrics, get_donation_count, get_donor_count, get_release_count, and get_total_tx_count for dashboard and export workflows.
MilestoneX is an on-chain crowdfunding protocol built on the Stellar Network and Soroban smart contracts. It provides a transparent, trust-minimized platform where campaign creators can raise funds in native XLM or any Stellar-based asset (USDC, NGNT, custom tokens), and donors retain full visibility into how their contributions are deployed.
The protocol is governed by a set of deterministic Soroban contracts β handling campaign lifecycle management, milestone-based fund release, multi-asset donation processing, and cross-chain token bridging β complemented by a comprehensive CLI toolchain for deployment, transaction signing, wallet integration, and network diagnostics.
This project uses a Rust Cargo workspace with the following structure:
milestonex-contract/
|-- campaign/ # Canonical campaign contract
| |-- Cargo.toml
| `-- src/
| `-- lib.rs
βββ Cargo.toml # Workspace configuration
βββ crates/
β βββ contracts/
β β βββ core/ # Legacy compatibility/reference contract
β β βββ Cargo.toml
β β βββ src/
β β βββ lib.rs # Contract implementation
β βββ tools/ # CLI utilities and deployment tools
β βββ Cargo.toml
β βββ src/
β βββ main.rs # CLI entry point
βββ .gitignore
βββ README.md
milestonex-campaign: Canonical Soroban crowdfunding contract for milestones, multi-asset donations, refunds, lifecycle controls, and analyticsmilestonex-core: Legacy compatibility/reference contract; do not use for new campaign featuresmilestonex-tools: Advanced CLI utilities for contract deployment, configuration, transaction management, and debugging
The milestonex-cli binary (in crates/tools) ships with a focused set of
sub-commands today. Anything not listed below is unimplemented and will
print either β Unknown command: β¦ or a stubbed "not yet implemented"
banner with an issue link. Older documentation referenced several commands
that do not exist yet; the canonical status table lives in
docs/deployment.md and
is tracked in issue #37.
configβ Print resolved environment and active network.networkβ Print active Soroban network (RPC, Horizon, passphrase).vaultβ Show SecureVault status and security best practices.toggle <testnet|mainnet>β Switch the active network profile.
asset configβ Show asset configuration.asset generateβ Generate issuing keypair.asset checkβ Check issuing readiness.asset trustline <holder> [asset_code]β Establish a trustline.asset issue <recipient> <amount>β Issue assets to a recipient.
keymanager encrypt <password> <secret_key>β Encrypt a Stellar secret key.keymanager decrypt <password> <encrypted_hex>β Decrypt back to a secret key.keymanager init-vault <password>β Initialize an encrypted vault.keymanager vault-status/vault-save <path>/vault-load <path> <password>β Vault lifecycle.
keypair generate-masterβ Generate a master keypair.keypair generate-distribution <issuing_public_key>β Generate a distribution account.keypair show-master/keypair show-distributionβ Print stored keypairs (safe view).keypair fund <account_public_key> <amount_xlm>β Friendbot-fund a testnet account.keypair validate-master/keypair validate-distributionβ Validate stored keypairs.
signing build-donation <donor> <campaign_id> <amount> [asset] [memo]β Build a donation signing request.signing build-campaign <creator> <title> <goal> <deadline>β Build a campaign creation request.signing build-custom <xdr> [description]β Wrap an external XDR.signing validate <json_file>/signing export <json_file>β Validate or export.response process <json>/response validate <file>/response save <json> <file>/response load <file>β Wallet response lifecycle.response submit <file>β Placeholder for native network submission (tracked in #37).
# Inspect active configuration and network
milestonex-cli config
milestonex-cli network
milestonex-cli toggle testnet
# Issue a custom asset and establish trustline
milestonex-cli asset generate
milestonex-cli asset trustline GABJ2... USDC
milestonex-cli asset issue GABJ2... 100
# Build a donation signing request for a donor
milestonex-cli signing build-donation GBJCHU... 1 5000000 XLM "Supporting education"
# Process the wallet's signed response
milestonex-cli response process '{"requestId":"req_123","xdr":"AAAA...","signer":"GBJCHU...","signedAt":1234567890}'For the full command list, run milestonex-cli with no arguments.
wallet_connect.html is a single-file browser application that provides a full
donation UX for any deployed milestonex-campaign contract instance. It is
generated by a small Webpack build in the wallet-client/ directory and bundles
@stellar/stellar-sdk and @stellar/freighter-api so it has zero runtime
dependencies.
- Freighter wallet lifecycle β connect, authorize, and disconnect using the Freighter browser extension.
- Campaign ID query param β share links like
wallet_connect.html?campaign=<CONTRACT_ID>to deep-link directly into a specific deployed campaign. - Campaign state display β shows goal, total raised, donor count, donation count, days remaining, progress bar, and all milestones (Locked / Unlocked / Released) with a β» Refresh button.
- Multi-asset donation form β drop-down pre-populated from the campaign's
accepted_assets, supports native XLM and any Stellar asset (USDC, NGNT, etc.). - Soroban XDR signing β builds an
invokeHostFunctiontransaction viastellar-sdk, simulates it to obtain the footprint, presents the assembled XDR to Freighter for signing, then displays the signed XDR for review. - One-click submit β submits the signed XDR to the Soroban RPC, polls for confirmation, shows the transaction hash with an Explorer link, and auto-refreshes the campaign state.
- Testnet / mainnet β automatically selects the correct Horizon and RPC endpoints based on the network reported by Freighter.
cd wallet-client
npm install
npm run build # writes wallet_connect.html to the project rootFor development with live reload:
npm run dev # starts webpack-dev-server at http://localhost:3000- Open
wallet_connect.htmlin a browser that has the Freighter extension installed. - Paste a deployed campaign contract ID into the Campaign field and click
Load (or pass
?campaign=<ID>in the URL). - Click Connect Freighter and approve the connection.
- Enter an amount (in stroops β 1 XLM = 10 000 000 stroops), select an asset, add an optional memo, and click Sign & Donate.
- Approve the transaction in Freighter.
- Review the signed XDR in the Signed XDR panel, then click Submit to Network.
- The transaction hash and a Stellar Explorer link appear once confirmed.
wallet-client/
βββ package.json # npm dependencies + build scripts
βββ webpack.config.js # bundles everything into a single HTML file
βββ src/
βββ index.js # all wallet/signing/campaign logic
βββ template.html # HTML template (Webpack inlines the JS bundle)
-
Clone the repository
git clone https://github.com/YOUR_USERNAME/milestonex-contract.git cd milestonex-contract -
Install Rust toolchain (automatically configured by
rust-toolchain.toml)# Install Rust if not already installed curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # The project will automatically use the correct Rust version and targets rustup show
-
Install Soroban CLI
# Method 1: Install via cargo (recommended for development) cargo install soroban-cli # Method 2: Install via npm (alternative) npm install -g soroban-cli # Verify installation soroban --version
-
Build the project
# Using Make (recommended) make build # Or using cargo directly cargo build -p milestonex-campaign --target wasm32v1-none
- Rust stable toolchain (automatically managed by
rust-toolchain.toml) - wasm32v1-none target (auto-installed by toolchain)
- Soroban CLI for contract deployment and testing
This project uses rust-toolchain.toml to ensure consistent development environments:
[toolchain]
channel = "stable"
targets = ["wasm32v1-none"]
components = ["rustfmt", "clippy"]This ensures:
- Consistent Rust version across all contributors
- Required targets are automatically installed
- Essential components (rustfmt, clippy) are included
The project includes a Makefile for common development tasks:
# Build WASM contract
make build
# Run all tests
make test
# Format code
make fmt
# Run linter
make lint
# Clean build artifacts
make clean
# Show all available commands
make help# Build the canonical campaign contract for WASM
cargo build -p milestonex-campaign --target wasm32v1-none --release
# Build the CLI tools
cargo build -p milestonex-tools
# Build entire workspace
cargo build --workspace# Run canonical campaign contract tests
cargo test -p milestonex-campaign
# Run all tests
cargo test --workspaceThe commands below match
crates/tools/src/main.rsand the canonical status table indocs/deployment.md.deployandinvokeare currently stubs in the CLI binary; use the nativestellar contract β¦commands ormake deploy-testnetinstead.accountis deprecated but still functional β it delegates tokeypaircommands with a deprecation warning.config init,contract-id,build-donation-tx,submit-tx,verify-tx,prepare-wallet-signing, andcomplete-wallet-signingshown in older docs are not implemented β see issue #37.
# Inspect resolved configuration / network / vault
cargo run -p milestonex-tools -- config
cargo run -p milestonex-tools -- network
cargo run -p milestonex-tools -- vault
cargo run -p milestonex-tools -- toggle testnet
# Issue assets via the asset namespace
cargo run -p milestonex-tools -- asset config
cargo run -p milestonex-tools -- asset generate
cargo run -p milestonex-tools -- asset trustline GABJ2... USDC
cargo run -p milestonex-tools -- asset issue GABJ2... 100
# Encrypted vault operations
cargo run -p milestonex-tools -- keymanager init-vault "$VAULT_MASTER_PASSWORD"
cargo run -p milestonex-tools -- keymanager vault-status
# Keypair lifecycle (the entry point that replaced `account create|fund`)
cargo run -p milestonex-tools -- keypair generate-master
cargo run -p milestonex-tools -- keypair fund GABJ2... 10
# Wallet signing + response
cargo run -p milestonex-tools -- signing build-donation GBJCHU... 1 5000000 XLM "Supporting education"
cargo run -p milestonex-tools -- response process '{"requestId":"req_123","xdr":"AAAA...","signer":"GBJCHU...","signedAt":1234567890}'This guide walks you through deploying the canonical campaign contract to testnet and invoking a health-check method.
-
Install Soroban CLI:
cargo install soroban-cli
-
Generate a keypair (for testnet):
soroban keys generate test_account --network testnet
-
Get testnet XLM (optional but recommended for testing):
- Visit Stellar Testnet Faucet
# Build WASM contracts (campaign + core + token-bridge + common)
make build-wasm
# Or build everything including CLI tools
make build# Copy the example environment file
cp .env.example .env
# Edit .env and set your admin key:
# SOROBAN_ADMIN_KEY=YOUR_PUBLIC_KEYOr generate and configure a new key:
# Generate a new keypair
soroban keys generate my_admin --network testnet
# Get the public key
soroban keys list
# Add to .env
SOROBAN_ADMIN_KEY=GA7...The in-CLI
deploycommand is a stub today. Use the build-in Makefile target (orscripts/deploy.sh) which is wired intostellar contract deployfor real network output. Tracking: issue #37.
# Deploy via the Makefile wrapper (uses scripts/deploy.sh + stellar-cli)
make deploy-testnet
# Or invoke the deploy script directly:
bash scripts/deploy.sh testnetExpected output:
βΉοΈ Using optimized WASM: target/wasm32v1-none/release/milestonex_core.wasm
π Deploying to testnet...
RPC: https://soroban-testnet.stellar.org:443
WASM: target/wasm32v1-none/release/milestonex_core.wasm
β
Contract deployed!
π Contract ID: CB7...ABC
πΎ Deployment record saved to deployments/testnet.json
β
Contract ID stored in .milestonex_contract_id
The in-CLI
invokecommand is also a stub. Usestellar contract invokenatively against your deployed contract ID.
# Read the contract ID that Step 3 wrote out
CONTRACT_ID=$(cat .milestonex_contract_id)
# Invoke a contract method (replace `version` with any contract method such as `ping`)
stellar contract invoke \
--id "$CONTRACT_ID" \
--source test_account \
--network testnet \
-- versionExpected output:
π Invoking method 'version' on network: testnet
π Using contract ID: CB7...ABC
β
Invocation successful!
π€ Result: <contract version bytes>
# View the deployed contract ID written by scripts/deploy.sh
cat .milestonex_contract_id
# View the per-network deployment record
cat deployments/testnet.json
# View active network configuration
cargo run -p milestonex-tools -- networkFor local testing without testnet:
# Start local sandbox (requires Docker)
make sandbox-start
# Deploy to sandbox (uses scripts/deploy.sh sandbox)
make deploy-sandbox
# Invoke on sandbox natively
CONTRACT_ID=$(cat .milestonex_contract_id)
stellar contract invoke \
--id "$CONTRACT_ID" \
--source test_account \
--rpc-url http://localhost:8000/soroban/rpc \
--network-passphrase "Standalone Network ; February 2017" \
-- version- "WASM file not found": Run
make build-wasmto build the contracts first. - "Unknown command" or "coming soon": You ran an
milestonex-clicommand that is still a stub (deploy,invoke). Runcargo run -p milestonex-toolswith no arguments to see which commands are actually implemented, and followdocs/deployment.md. - "No contract ID found": Run
make deploy-testnetfirst β thescripts/deploy.shwrapper writes the ID to.milestonex_contract_id. - "Configuration error": Run
cargo run -p milestonex-tools -- configto inspect resolved environment values. - "soroban: command not found": Install with
cargo install --locked stellar-cli --features opt.
- Discover global fundraising campaigns
- Donate in XLM or Stellar assets
- Wallet integration (Freighter, Albedo, Lobstr)
- On-chain transparency: verify all transactions
- Create social impact projects
- Accept multi-asset contributions
- Real-time donation tracking
- Withdraw funds directly on-chain
- Campaign approval workflow
- User & KYC management
- Analytics dashboard
MilestoneX Blockchain Layer is built with:
- Stellar Testnet / Mainnet support
- Donation verification
- On-chain withdrawal system
- Assetβagnostic design
MilestoneX includes a comprehensive fee estimation service that provides accurate transaction fee calculations, surge pricing detection, and multi-currency conversion.
- Real-time Fee Estimation: Fetch current base fees from Stellar Horizon
- Surge Pricing Detection: 4-level detection (Normal, Elevated, High, Critical)
- Multi-Currency Display: Convert fees to 10+ supported currencies
- Caching: 5-minute TTL cache to reduce API calls
- Fee History Tracking: 1000+ records for analytics and trend detection
use fee::FeeEstimationService;
#[tokio::main]
async fn main() -> Result<()> {
let service = FeeEstimationService::public_horizon();
// Estimate fee for 2-operation donation
let fee_info = service.estimate_fee(2).await?;
println!("Fee: {:.8} XLM", fee_info.total_fee_xlm);
// Check for surge pricing
if fee_info.is_surge_pricing {
println!("β οΈ Network surging at {}%!", fee_info.surge_percent as i64);
}
Ok(())
}- Base Fee: 100 stroops (0.00001 XLM)
- Conversion: 1 XLM = 10,000,000 stroops
- Cache TTL: 300 seconds (5 minutes)
Click the βForkβ button in the topβright of the GitHub repo and clone your fork:
git clone https://github.com/YOUR_USERNAME/milestonex-contract.git
cd milestonex-contractgit checkout -b feature/add-donation-flowUse conventional commits:
feat: add wallet connection modal
fix: resolve donation API error
docs: update project README
refactor: clean up project creation formPush your branch:
git push origin feature/add-donation-flowOpen a Pull Request from your fork back to the main branch.
This project uses cargo-audit and cargo-deny to maintain high security standards and license compliance.
You can run the security scans locally using the following commands:
- Check for vulnerabilities:
make audit
- Check for license and ban policies:
make deny
If a vulnerability is found, you should:
- Update dependencies: Run
cargo updateto see if a newer version of the crate resolves the issue. - Ignore (Temporary): If a fix is not available and you have audited the vulnerability, you can temporarily ignore it by adding it to the
[advisories] -> ignorelist in the deny configuration.
If a license or ban policy violation is found:
- Check Licenses: Ensure all dependencies use approved licenses. If a new license needs to be allowed, update the
allowlist indeny.toml. - Banned Crates: If a crate is banned, you must find an alternative or justify its use and add it to the
skiplist indeny.toml.
Security scans are automatically run on every push and pull request. CI will fail if any known vulnerabilities or policy violations are detected.
MIT License β free to use, modify, and distribute.
This workspace includes a deterministic, strongly-typed Soroban network configuration system.
Add a network (example CLI stub):
soroban config network add <name> \
--rpc-url <url> \
--network-passphrase "<passphrase>"List networks (profiles in soroban.toml):
soroban config network lsSelect a network (this sets the active profile name; loader reads SOROBAN_NETWORK):
soroban config network use <name>Environment variable override behavior
SOROBAN_NETWORKselects a profile (e.g.testnet,mainnet,sandbox).SOROBAN_RPC_URLandSOROBAN_NETWORK_PASSPHRASEoverride profile values when set.
Verify the resolved network with the included CLI tool:
cargo run -p milestonex-tools -- networkSee .env.example for a safe example of environment variables you can copy to .env.