diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml new file mode 100644 index 0000000..53c10c2 --- /dev/null +++ b/.github/workflows/contracts.yml @@ -0,0 +1,84 @@ +name: Contracts CI + +on: + push: + branches: [main, develop] + paths: + - 'contracts/**' + - '.github/workflows/contracts.yml' + pull_request: + branches: [main, develop] + paths: + - 'contracts/**' + - '.github/workflows/contracts.yml' + +jobs: + test-contracts: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: wasm32-unknown-unknown + components: clippy, rustfmt + override: true + + - name: Cache Cargo registry + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + contracts/target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Run cargo test + working-directory: contracts/contracts/boxmeout + run: cargo test --features testutils + + - name: Run cargo clippy + working-directory: contracts/contracts/boxmeout + run: cargo clippy --all-targets --features testutils -- -D warnings + + - name: Check formatting + working-directory: contracts/contracts/boxmeout + run: cargo fmt -- --check + + - name: Build WASM contracts + working-directory: contracts/contracts/boxmeout + run: cargo build --release --target wasm32-unknown-unknown + + - name: List WASM artifacts + run: | + ls -lh contracts/target/wasm32-unknown-unknown/release/*.wasm + find contracts/target -name "*.wasm" -type f + + - name: Install cargo-tarpaulin + run: cargo install cargo-tarpaulin + + - name: Generate test coverage + working-directory: contracts/contracts/boxmeout + run: cargo tarpaulin --features testutils --out Xml --output-dir coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: contracts/contracts/boxmeout/coverage/cobertura.xml + flags: contracts + name: contract-coverage + fail_ci_if_error: false + + - name: Upload WASM artifacts + uses: actions/upload-artifact@v4 + with: + name: contract-wasm + path: contracts/target/wasm32-unknown-unknown/release/boxmeout.wasm + retention-days: 7 diff --git a/check-all.sh b/check-all.sh old mode 100644 new mode 100755 diff --git a/contracts/contracts/boxmeout/src/market.rs b/contracts/contracts/boxmeout/src/market.rs index 005ae3e..01aabd3 100644 --- a/contracts/contracts/boxmeout/src/market.rs +++ b/contracts/contracts/boxmeout/src/market.rs @@ -180,6 +180,7 @@ pub struct PredictionMarket; #[contractimpl] impl PredictionMarket { /// Initialize a single market instance + #[allow(clippy::too_many_arguments)] pub fn initialize( env: Env, market_id: BytesN<32>, @@ -1123,10 +1124,20 @@ impl PredictionMarket { .set(&Symbol::new(&env, MARKET_STATE_KEY), &STATE_CANCELLED); let timestamp = env.ledger().timestamp(); - env.events().publish( - (Symbol::new(&env, "MarketCancelled"),), - (market_id, creator, timestamp), - ); + + #[contractevent] + pub struct MarketCancelledEvent { + pub market_id: BytesN<32>, + pub creator: Address, + pub timestamp: u64, + } + + MarketCancelledEvent { + market_id, + creator, + timestamp, + } + .publish(&env); } // --- TEST HELPERS (Not for production use, but exposed for integration tests) --- diff --git a/contracts/contracts/boxmeout/src/oracle.rs b/contracts/contracts/boxmeout/src/oracle.rs index 26b2a43..1139d31 100644 --- a/contracts/contracts/boxmeout/src/oracle.rs +++ b/contracts/contracts/boxmeout/src/oracle.rs @@ -948,16 +948,23 @@ impl OracleManager { .set(&Symbol::new(&env, LAST_OVERRIDE_TIME_KEY), ¤t_time); // 12. Emit EmergencyOverride event with all details - env.events().publish( - (Symbol::new(&env, "EmergencyOverride"),), - ( - market_id, - forced_outcome, - justification_hash, - approvers, - current_time, - ), - ); + #[contractevent] + pub struct EmergencyOverrideEvent { + pub market_id: BytesN<32>, + pub forced_outcome: u32, + pub justification_hash: BytesN<32>, + pub approvers: Vec
, + pub timestamp: u64, + } + + EmergencyOverrideEvent { + market_id, + forced_outcome, + justification_hash, + approvers, + timestamp: current_time, + } + .publish(&env); } /// Get emergency override record for a market (for audit purposes) diff --git a/contracts/contracts/boxmeout/tests/factory_test.rs b/contracts/contracts/boxmeout/tests/factory_test.rs index edeff16..8d7ecde 100644 --- a/contracts/contracts/boxmeout/tests/factory_test.rs +++ b/contracts/contracts/boxmeout/tests/factory_test.rs @@ -268,6 +268,7 @@ fn register_factory(env: &Env) -> Address { } // Helper to create a mock USDC token +#[allow(dead_code)] fn create_mock_token(env: &Env, admin: &Address) -> Address { let token_address = env.register_stellar_asset_contract_v2(admin.clone()); token_address.address() diff --git a/contracts/contracts/boxmeout/tests/integration_test.rs b/contracts/contracts/boxmeout/tests/integration_test.rs index 83424f7..ccfdf91 100644 --- a/contracts/contracts/boxmeout/tests/integration_test.rs +++ b/contracts/contracts/boxmeout/tests/integration_test.rs @@ -42,8 +42,8 @@ fn test_complete_prediction_flow() { let admin = Address::generate(&env); let usdc_token = Address::generate(&env); let _creator = Address::generate(&env); - let user1 = Address::generate(&env); - let user2 = Address::generate(&env); + let _user1 = Address::generate(&env); + let _user2 = Address::generate(&env); // Step 2: Initialize all contracts factory_client.initialize(&admin, &usdc_token, &treasury_id); @@ -120,8 +120,7 @@ fn test_complete_prediction_flow() { // let platform_fees = treasury_client.get_platform_fees(); // assert!(platform_fees > 0); - // Verify complete flow succeeded - assert!(true); // Placeholder until functions implemented + // Verify complete flow succeeded - test passes if no panics occurred } /// Integration test: Market creation and AMM trading flow diff --git a/contracts/contracts/boxmeout/tests/market_test.rs b/contracts/contracts/boxmeout/tests/market_test.rs index 435f0ea..6434af0 100644 --- a/contracts/contracts/boxmeout/tests/market_test.rs +++ b/contracts/contracts/boxmeout/tests/market_test.rs @@ -1,6 +1,6 @@ #![cfg(test)] -use boxmeout::market::{MarketError, MarketState, PredictionMarketClient}; +use boxmeout::market::{MarketError, PredictionMarketClient}; use soroban_sdk::{ testutils::{Address as _, Ledger, LedgerInfo}, token, Address, BytesN, Env, Symbol, @@ -156,7 +156,7 @@ fn test_market_initialize() { #[test] fn test_commit_prediction_happy_path() { let env = create_test_env(); - let (client, _market_id, _creator, admin, usdc_address, _market_contract) = + let (client, _market_id, _creator, _admin, usdc_address, _market_contract) = setup_test_market(&env); // Setup user with USDC balance @@ -205,7 +205,7 @@ fn test_commit_prediction_happy_path() { #[test] fn test_commit_prediction_duplicate_rejected() { let env = create_test_env(); - let (client, _market_id, _creator, admin, usdc_address, _market_contract) = + let (client, _market_id, _creator, _admin, usdc_address, _market_contract) = setup_test_market(&env); let user = Address::generate(&env); @@ -271,7 +271,7 @@ fn test_commit_prediction_negative_amount_rejected() { #[test] fn test_multiple_users_commit() { let env = create_test_env(); - let (client, _market_id, _creator, admin, usdc_address, _market_contract) = + let (client, _market_id, _creator, _admin, usdc_address, _market_contract) = setup_test_market(&env); let token = token::StellarAssetClient::new(&env, &usdc_address); @@ -912,5 +912,5 @@ fn test_get_market_state_serializable() { let _winning_outcome = state.winning_outcome; // If we got here, the struct is properly serializable - assert!(true); + // Verification complete }