diff --git a/.gitignore b/.gitignore index e5429879..92b8f3d0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ target # Local settings .soroban .stellar +temp_auto_push.bat contracts/predictify-hybrid/test_snapshots # Environment variables (never commit secrets!) .env .env.* -*.env \ No newline at end of file +*.env.gitignore +branch_structure.json diff --git a/contracts/predictify-hybrid/src/event_topic_catalog.rs b/contracts/predictify-hybrid/src/event_topic_catalog.rs index c163858e..d005b3d9 100644 --- a/contracts/predictify-hybrid/src/event_topic_catalog.rs +++ b/contracts/predictify-hybrid/src/event_topic_catalog.rs @@ -40,6 +40,7 @@ pub fn get_event_topic_catalog(env: &Env) -> Vec { ("accumulate_dispute_fee", "dispute_fee_accumulated", "Fired when a dispute fee is accumulated"), ("set_governance_min_bet_bps", "governance_min_bet_updated", "Fired when governance updates min bet bps"), ("update_rate_limits", "rate_limits_updated", "Fired when an admin updates the rate-limit configuration"), + ("upgrade", "contract_upgraded", "Fired when the contract WASM is upgraded"), ]; for (entrypoint, topic, description) in entries { @@ -80,4 +81,12 @@ mod tests { let found = catalog.iter().any(|e| e.topic == String::from_str(&env, "rate_limits_updated")); assert!(found); } + + #[test] + fn test_catalog_contains_contract_upgraded() { + let env = Env::default(); + let catalog = get_event_topic_catalog(&env); + let found = catalog.iter().any(|e| e.topic == String::from_str(&env, "contract_upgraded")); + assert!(found); + } } diff --git a/contracts/predictify-hybrid/src/slim_upgrade_tests.rs b/contracts/predictify-hybrid/src/slim_upgrade_tests.rs new file mode 100644 index 00000000..dd38e5c3 --- /dev/null +++ b/contracts/predictify-hybrid/src/slim_upgrade_tests.rs @@ -0,0 +1,176 @@ +#![allow(dead_code)] +#![allow(unused_imports)] + +use soroban_sdk::{ + testutils::{Address as _, MockAuth, MockAuthInvoke}, + Address, BytesN, Env, IntoVal, +}; + +use crate::{Error, PredictifyHybrid, PredictifyHybridClient}; + +/// Upload a tiny test WASM and return its hash. The `test_wasm/hello_world.wasm` +/// fixture is a minimal valid WASM module used as a real, deployable upgrade +/// target. +fn test_wasm_hash(env: &Env) -> BytesN<32> { + let wasm: &[u8] = include_bytes!("../test_wasm/hello_world.wasm"); + env.deployer().upload_contract_wasm(wasm) +} + +fn setup(env: &Env) -> (PredictifyHybridClient<'_>, Address) { + let admin = Address::generate(env); + let contract_id = env.register(PredictifyHybrid, ()); + let client = PredictifyHybridClient::new(env, &contract_id); + client.initialize(&admin); + (client, admin) +} + +/// Row 1: admin `upgrade` with the correct predecessor and a single +/// `MockAuth` succeeds, the stored hash is updated, and the event is emitted. +#[test] +fn slim_upgrade_admin_succeeds() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + + let new_hash = test_wasm_hash(&env); + + env.mock_auths(&[MockAuth { + address: &admin, + invoke: &MockAuthInvoke { + contract: &client.address, + fn_name: "upgrade", + args: (admin.clone(), new_hash.clone(), genesis.clone()).into_val(&env), + sub_invokes: &[], + }, + }]); + + client.upgrade(&admin, &new_hash, &genesis); + assert_eq!(client.get_current_wasm_hash(), new_hash); +} + +/// Row 2: a non-admin upgrade is rejected with `Unauthorized`. +#[test] +fn slim_upgrade_non_admin_unauthorized() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + let attacker = Address::generate(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + let new_hash = test_wasm_hash(&env); + + let res = client.try_upgrade(&attacker, &new_hash, &genesis); + assert_eq!(res, Err(Ok(Error::Unauthorized))); +} + +/// Row 3: a wrong expected predecessor is rejected by the chain check. +#[test] +fn slim_upgrade_wrong_predecessor_rejected() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + let new_hash = test_wasm_hash(&env); + let wrong = BytesN::from_array(&env, &[9u8; 32]); + + let res = client.try_upgrade(&admin, &new_hash, &wrong); + assert!(res.is_err()); +} + +/// Row 4: a zero predecessor is rejected once the current hash has been seeded. +#[test] +fn slim_upgrade_zero_predecessor_after_seed_rejected() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + let new_hash = test_wasm_hash(&env); + let zero = BytesN::from_array(&env, &[0u8; 32]); + + let res = client.try_upgrade(&admin, &new_hash, &zero); + assert!(res.is_err()); +} + +/// Row 5: `set_initial_wasm_hash` is one-shot; the second call is rejected. +#[test] +fn set_initial_wasm_hash_twice_rejected() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + + let res = client.try_set_initial_wasm_hash(&admin, &genesis); + assert!(res.is_err()); +} + +/// Row 6: the full `upgrade_contract` path authenticates exactly once. +#[cfg(feature = "full")] +#[test] +fn full_upgrade_contract_single_auth() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + let new_hash = test_wasm_hash(&env); + + env.mock_auths(&[MockAuth { + address: &admin, + invoke: &MockAuthInvoke { + contract: &client.address, + fn_name: "upgrade_contract", + args: (admin.clone(), new_hash.clone(), genesis.clone()).into_val(&env), + sub_invokes: &[], + }, + }]); + + client.upgrade_contract(&admin, &new_hash, &genesis); + assert_eq!(client.get_current_wasm_hash(), new_hash); +} + +/// Row 7: the full `rollback_upgrade` path authenticates exactly once. +#[cfg(feature = "full")] +#[test] +fn full_rollback_upgrade_single_auth() { + let env = Env::default(); + env.mock_all_auths(); + let (client, admin) = setup(&env); + + let genesis = test_wasm_hash(&env); + client.set_initial_wasm_hash(&admin, &genesis); + let new_hash = test_wasm_hash(&env); + + env.mock_auths(&[MockAuth { + address: &admin, + invoke: &MockAuthInvoke { + contract: &client.address, + fn_name: "upgrade_contract", + args: (admin.clone(), new_hash.clone(), genesis.clone()).into_val(&env), + sub_invokes: &[], + }, + }]); + client.upgrade_contract(&admin, &new_hash, &genesis); + + env.mock_auths(&[MockAuth { + address: &admin, + invoke: &MockAuthInvoke { + contract: &client.address, + fn_name: "rollback_upgrade", + args: (admin.clone(), genesis.clone(), new_hash.clone()).into_val(&env), + sub_invokes: &[], + }, + }]); + client.rollback_upgrade(&admin, &genesis, &new_hash); + assert_eq!(client.get_current_wasm_hash(), genesis); +} diff --git a/public/fonts/README.md b/public/fonts/README.md new file mode 100644 index 00000000..1e4f9ba1 --- /dev/null +++ b/public/fonts/README.md @@ -0,0 +1,24 @@ +# Fonts Directory + +This directory contains custom fonts for the Blockchain Explorer application. + +## Required Font Files + +The application expects the following font files: + +1. **BlockchainFont-Regular.woff2** and **BlockchainFont-Regular.woff** + - Regular weight font for the main UI + +2. **BlockchainFont-Bold.woff2** and **BlockchainFont-Bold.woff** + - Bold weight font for headings + +3. **TechMono-Regular.woff2** and **TechMono-Regular.woff** + - Monospace font for code and hash displays + +## Note + +If you don't have custom fonts, the application will fall back to system fonts: +- BlockchainFont → system sans-serif fonts +- TechMono → system monospace fonts (Courier New, etc.) + +The fonts are referenced in `public/index.html` and will be loaded automatically when available. diff --git a/public/fonts/fa-brands-400.eot b/public/fonts/fa-brands-400.eot new file mode 100644 index 00000000..a1bc094a Binary files /dev/null and b/public/fonts/fa-brands-400.eot differ diff --git a/public/fonts/fa-brands-400.svg b/public/fonts/fa-brands-400.svg new file mode 100644 index 00000000..46ad237a --- /dev/null +++ b/public/fonts/fa-brands-400.svg @@ -0,0 +1,3570 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-brands-400.ttf b/public/fonts/fa-brands-400.ttf new file mode 100644 index 00000000..948a2a6c Binary files /dev/null and b/public/fonts/fa-brands-400.ttf differ diff --git a/public/fonts/fa-brands-400.woff b/public/fonts/fa-brands-400.woff new file mode 100644 index 00000000..2a89d521 Binary files /dev/null and b/public/fonts/fa-brands-400.woff differ diff --git a/public/fonts/fa-brands-400.woff2 b/public/fonts/fa-brands-400.woff2 new file mode 100644 index 00000000..141a90a9 Binary files /dev/null and b/public/fonts/fa-brands-400.woff2 differ diff --git a/public/fonts/fa-regular-400.eot b/public/fonts/fa-regular-400.eot new file mode 100644 index 00000000..38cf2517 Binary files /dev/null and b/public/fonts/fa-regular-400.eot differ diff --git a/public/fonts/fa-regular-400.svg b/public/fonts/fa-regular-400.svg new file mode 100644 index 00000000..48634a9a --- /dev/null +++ b/public/fonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-regular-400.ttf b/public/fonts/fa-regular-400.ttf new file mode 100644 index 00000000..abe99e20 Binary files /dev/null and b/public/fonts/fa-regular-400.ttf differ diff --git a/public/fonts/fa-regular-400.woff b/public/fonts/fa-regular-400.woff new file mode 100644 index 00000000..24de566a Binary files /dev/null and b/public/fonts/fa-regular-400.woff differ diff --git a/public/fonts/fa-regular-400.woff2 b/public/fonts/fa-regular-400.woff2 new file mode 100644 index 00000000..7e0118e5 Binary files /dev/null and b/public/fonts/fa-regular-400.woff2 differ diff --git a/public/fonts/fa-solid-900.eot b/public/fonts/fa-solid-900.eot new file mode 100644 index 00000000..d3b77c22 Binary files /dev/null and b/public/fonts/fa-solid-900.eot differ diff --git a/public/fonts/fa-solid-900.svg b/public/fonts/fa-solid-900.svg new file mode 100644 index 00000000..7742838b --- /dev/null +++ b/public/fonts/fa-solid-900.svg @@ -0,0 +1,4938 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-solid-900.ttf b/public/fonts/fa-solid-900.ttf new file mode 100644 index 00000000..5b979039 Binary files /dev/null and b/public/fonts/fa-solid-900.ttf differ diff --git a/public/fonts/fa-solid-900.woff b/public/fonts/fa-solid-900.woff new file mode 100644 index 00000000..beec7917 Binary files /dev/null and b/public/fonts/fa-solid-900.woff differ diff --git a/public/fonts/fa-solid-900.woff2 b/public/fonts/fa-solid-900.woff2 new file mode 100644 index 00000000..978a681a Binary files /dev/null and b/public/fonts/fa-solid-900.woff2 differ