Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,44 @@ jobs:
cache-on-failure: true
- name: cargo check --target wasm32v1-none (contracts)
run: cargo check ${{ env.CONTRACTS }} --target wasm32v1-none

bindings-check:
name: Bindings freshness check
runs-on: ubuntu-latest
timeout-minutes: 30
# Needs write access to annotate diff output; all other jobs stay read-only.
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain with wasm target
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32v1-none
cache: false
- name: Cache cargo registry and target
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Build campaign WASM (release)
run: cargo build -p milestonex-campaign --target wasm32v1-none --release
- name: Install stellar CLI
# Install the same CLI used in development (see `make setup`).
# --locked pins the dependency tree; --features opt enables the
# optimised build which includes the `contract bindings` sub-command.
run: cargo install --locked stellar-cli --features opt
- name: Regenerate bindings
run: |
mkdir -p bindings
stellar contract bindings json \
--wasm target/wasm32v1-none/release/milestonex_campaign.wasm \
--out bindings/
- name: Fail if bindings are stale
run: |
if ! git diff --exit-code bindings/milestonex_campaign.json; then
echo ""
echo "❌ bindings/milestonex_campaign.json is stale."
echo " Run 'make bindings' locally and commit the updated file."
exit 1
fi
echo "✅ Bindings are up to date."
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
## make deny - Check licenses
## make fmt - Format code
## make clippy - Lint code
## make bindings - Generate JSON ABI bindings for the campaign contract

.PHONY: build build-wasm build-tools test fmt lint clean optimize help \
setup deploy-testnet deploy-sandbox sandbox-start audit deny
setup deploy-testnet deploy-sandbox sandbox-start audit deny bindings

# Default target
build: build-wasm build-tools
Expand Down Expand Up @@ -80,6 +81,17 @@ deploy-testnet: build-wasm
bash scripts/deploy.sh testnet


# Generate JSON ABI bindings for the canonical campaign contract.
# Requires: stellar CLI (cargo install --locked stellar-cli --features opt)
# Requires: WASM built first (make build-wasm)
bindings: build-wasm
@echo "📎 Generating contract bindings..."
@mkdir -p bindings
stellar contract bindings json \
--wasm target/wasm32v1-none/release/milestonex_campaign.wasm \
--out bindings/
@echo "✅ Bindings written to bindings/milestonex_campaign.json"

# Run cargo-audit for vulnerability scanning
audit:
@echo "🔒 Running security audit..."
Expand Down Expand Up @@ -113,4 +125,5 @@ help:
@echo " make deploy-sandbox - Deploy contract to local sandbox"
@echo " make deploy-testnet - Deploy contract to Stellar testnet"
@echo " make optimize - Optimize WASM with wasm-opt -Oz"
@echo " make bindings - Generate JSON ABI bindings for the campaign contract"
@echo " make help - Show this help message"
194 changes: 194 additions & 0 deletions bindings/milestonex_campaign.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
{
"contract_name": "milestonex_campaign",
"contract_id": null,
"network_passphrase": null,
"functions": [
{
"name": "initialize",
"doc": "Initialize a new campaign with strict validation on all inputs.",
"inputs": [
{ "name": "creator", "value": { "type": "address" } },
{ "name": "goal_amount", "value": { "type": "i128" } },
{ "name": "end_time", "value": { "type": "u64" } },
{ "name": "accepted_assets", "value": { "type": "vec", "items": { "type": "custom", "name": "StellarAsset" } } },
{ "name": "milestones", "value": { "type": "vec", "items": { "type": "custom", "name": "MilestoneData" } } },
{ "name": "min_donation_amount", "value": { "type": "i128" } }
],
"outputs": [
{ "type": "result", "value": { "type": "void" }, "error": { "type": "custom", "name": "Error" } }
]
},
{
"name": "donate",
"doc": "Donate to the campaign.",
"inputs": [
{ "name": "donor", "value": { "type": "address" } },
{ "name": "amount", "value": { "type": "i128" } },
{ "name": "asset", "value": { "type": "custom", "name": "AssetInfo" } }
],
"outputs": []
},
{
"name": "get_total_raised",
"doc": "Return the total amount raised across all assets.",
"inputs": [],
"outputs": [{ "type": "i128" }]
},
{
"name": "get_donation_count",
"doc": "Return the total number of donations.",
"inputs": [],
"outputs": [{ "type": "u64" }]
},
{
"name": "get_donor_count",
"doc": "Return the number of unique donors.",
"inputs": [],
"outputs": [{ "type": "u32" }]
},
{
"name": "get_release_count",
"doc": "Return the number of milestone releases.",
"inputs": [],
"outputs": [{ "type": "u64" }]
},
{
"name": "get_total_tx_count",
"doc": "Return the total transaction count.",
"inputs": [],
"outputs": [{ "type": "u64" }]
},
{
"name": "get_campaign_report",
"doc": "Return a full campaign report.",
"inputs": [],
"outputs": [{ "type": "option", "value": { "type": "custom", "name": "CampaignReport" } }]
},
{
"name": "get_platform_summary",
"doc": "Return a platform-level summary.",
"inputs": [],
"outputs": [{ "type": "custom", "name": "PlatformSummary" }]
},
{
"name": "get_dashboard_metrics",
"doc": "Return dashboard analytics metrics.",
"inputs": [],
"outputs": [{ "type": "custom", "name": "DashboardMetrics" }]
},
{
"name": "get_donor_record",
"doc": "Return the donor record for a given address.",
"inputs": [
{ "name": "donor", "value": { "type": "address" } }
],
"outputs": [{ "type": "option", "value": { "type": "custom", "name": "DonorRecord" } }]
},
{
"name": "hello",
"doc": "Health-check entry point.",
"inputs": [],
"outputs": [{ "type": "symbol" }]
},
{
"name": "version",
"doc": "Return the contract version.",
"inputs": [],
"outputs": [{ "type": "u32" }]
},
{
"name": "is_refund_eligible",
"doc": "Return whether a donor is eligible for a refund.",
"inputs": [
{ "name": "donor", "value": { "type": "address" } }
],
"outputs": [{ "type": "bool" }]
},
{
"name": "claim_refund",
"doc": "Claim a refund for a donor.",
"inputs": [
{ "name": "donor", "value": { "type": "address" } }
],
"outputs": []
},
{
"name": "end_campaign",
"doc": "End the campaign.",
"inputs": [],
"outputs": []
},
{
"name": "cancel_campaign",
"doc": "Cancel the campaign.",
"inputs": [],
"outputs": []
},
{
"name": "extend_deadline",
"doc": "Extend the campaign deadline.",
"inputs": [
{ "name": "new_end_time", "value": { "type": "u64" } }
],
"outputs": []
},
{
"name": "get_campaign_status",
"doc": "Return the current campaign status.",
"inputs": [],
"outputs": [{ "type": "custom", "name": "CampaignStatusResponse" }]
},
{
"name": "release_milestone",
"doc": "Release funds for a completed milestone (single asset).",
"inputs": [
{ "name": "milestone_index", "value": { "type": "u32" } },
{ "name": "recipient", "value": { "type": "address" } }
],
"outputs": []
},
{
"name": "release_milestone_multi_asset",
"doc": "Release funds for a completed milestone (multi-asset).",
"inputs": [
{ "name": "milestone_index", "value": { "type": "u32" } },
{ "name": "recipient", "value": { "type": "address" } }
],
"outputs": []
},
{
"name": "get_milestone_view",
"doc": "Return details for a specific milestone by index.",
"inputs": [
{ "name": "index", "value": { "type": "u32" } }
],
"outputs": [{ "type": "custom", "name": "MilestoneData" }]
},
{
"name": "get_all_milestones",
"doc": "Return all milestones with their current state.",
"inputs": [],
"outputs": [{ "type": "vec", "items": { "type": "custom", "name": "MilestoneView" } }]
},
{
"name": "upgrade",
"doc": "Upgrade the contract WASM.",
"inputs": [
{ "name": "new_wasm_hash", "value": { "type": "bytes_n", "n": 32 } }
],
"outputs": []
},
{
"name": "freeze",
"doc": "Freeze the contract, halting all state-changing operations.",
"inputs": [],
"outputs": []
},
{
"name": "unfreeze",
"doc": "Unfreeze the contract.",
"inputs": [],
"outputs": []
}
]
}
Loading