diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3053e54..ef2ee97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,12 +17,12 @@ jobs: - run: cargo fmt --all --check - - run: cargo clippy --all-targets --target x86_64-unknown-linux-gnu -- -D warnings + - run: cargo clippy --workspace --all-targets --target x86_64-unknown-linux-gnu -- -D warnings - - run: cargo test --all --target x86_64-unknown-linux-gnu + - run: cargo test --workspace --target x86_64-unknown-linux-gnu - name: WASM build - run: cargo build --target wasm32v1-none --release --all + run: cargo build --target wasm32v1-none --release --workspace - name: Report contract sizes run: | diff --git a/campaign/src/lib.rs b/campaign/src/lib.rs index b8586af..ea92d8d 100644 --- a/campaign/src/lib.rs +++ b/campaign/src/lib.rs @@ -1,4 +1,8 @@ #![no_std] + +pub mod storage; +pub mod types; + use soroban_sdk::{contract, contractimpl, Env}; #[contract] diff --git a/campaign/src/storage.rs b/campaign/src/storage.rs new file mode 100644 index 0000000..9c8c28b --- /dev/null +++ b/campaign/src/storage.rs @@ -0,0 +1,64 @@ +use soroban_sdk::{Address, Env}; + +use crate::types::{CampaignData, DataKey, DonorRecord, MilestoneData}; + +// ── Persistent storage helpers ──────────────────────────────────────────────── + +pub fn set_campaign(env: &Env, data: &CampaignData) { + env.storage().persistent().set(&DataKey::CampaignData, data); +} + +pub fn get_campaign(env: &Env) -> Option { + env.storage().persistent().get(&DataKey::CampaignData) +} + +pub fn set_milestone(env: &Env, index: u32, data: &MilestoneData) { + env.storage() + .persistent() + .set(&DataKey::MilestoneData(index), data); +} + +pub fn get_milestone(env: &Env, index: u32) -> Option { + env.storage() + .persistent() + .get(&DataKey::MilestoneData(index)) +} + +pub fn set_donor(env: &Env, donor: &Address, record: &DonorRecord) { + env.storage() + .persistent() + .set(&DataKey::DonorData(donor.clone()), record); +} + +pub fn get_donor(env: &Env, donor: &Address) -> Option { + env.storage() + .persistent() + .get(&DataKey::DonorData(donor.clone())) +} + +pub fn get_total_raised(env: &Env) -> i128 { + env.storage() + .persistent() + .get(&DataKey::TotalRaised) + .unwrap_or(0) +} + +pub fn set_total_raised(env: &Env, amount: i128) { + env.storage() + .persistent() + .set(&DataKey::TotalRaised, &amount); +} + +// ── Temporary storage helpers ───────────────────────────────────────────────── + +pub fn get_contract_status(env: &Env) -> Option { + env.storage() + .temporary() + .get(&DataKey::ContractStatus) +} + +pub fn set_contract_status(env: &Env, status: u32) { + env.storage() + .temporary() + .set(&DataKey::ContractStatus, &status); +} diff --git a/campaign/src/types.rs b/campaign/src/types.rs new file mode 100644 index 0000000..6e4f0de --- /dev/null +++ b/campaign/src/types.rs @@ -0,0 +1,87 @@ +use soroban_sdk::{contracttype, Address, BytesN, Vec}; + +// ── Supporting enums ───────────────────────────────────────────────────────── + +/// Issue #167 – campaign lifecycle status +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum CampaignStatus { + Active, + Successful, + Failed, + Cancelled, +} + +/// Issue #168 – milestone release status +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum MilestoneStatus { + Pending, + Released, + Cancelled, +} + +/// Accepted asset descriptor (native XLM or a Stellar asset) +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum AssetInfo { + Native, + Stellar(Address), +} + +// ── Issue #166 – storage key enum ──────────────────────────────────────────── + +/// All persistent storage keys used by the campaign contract. +/// Implements `contracttype` so Soroban can serialise it via XDR / `IntoVal`. +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum DataKey { + CampaignData, + MilestoneData(u32), + DonorData(Address), + TotalRaised, + ContractStatus, +} + +// ── Issue #167 – CampaignData struct ───────────────────────────────────────── + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CampaignData { + pub creator: Address, + pub goal_amount: i128, + pub raised_amount: i128, + pub end_time: u64, + pub status: CampaignStatus, + pub accepted_assets: Vec, + pub milestone_count: u32, +} + +// ── Issue #168 – MilestoneData struct ──────────────────────────────────────── + +/// Max 5 milestones enforced at the contract call site. +pub const MAX_MILESTONES: u32 = 5; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MilestoneData { + pub index: u32, + pub target_amount: i128, + pub description_hash: BytesN<32>, + pub status: MilestoneStatus, + pub released_at: Option, + pub release_tx: Option>, +} + +// ── Issue #169 – DonorRecord struct ────────────────────────────────────────── + +/// Stored under `DataKey::DonorData(donor_address)`. +/// Aggregated per-donor across multiple donations. +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DonorRecord { + pub donor: Address, + pub total_donated: i128, + pub asset: AssetInfo, + pub last_donation_time: u64, +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 86a51eb..f93e8e2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "stable" -targets = ["wasm32-unknown-unknown"] +targets = ["wasm32-unknown-unknown", "wasm32v1-none"] components = ["rustfmt", "clippy"]