Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ members = [
"contracts/multisig-governance",
"contracts/upgrade-governance",
"contracts/zk-eligibility-verifier",
"contracts/clinical-trial",
]
exclude = ["contracts/patient-registry/benches"]

Expand Down
15 changes: 9 additions & 6 deletions contracts/clinical-trial/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,20 @@ pub enum Error {
VisitNotFound = 15,
EventNotFound = 16,
TrialNotActive = 17,
AlreadyInitialized = 18,
}

#[contract]
pub struct ClinicalTrial;
pub struct ClinicalTrialContract;

#[contractimpl]
impl ClinicalTrial {
impl ClinicalTrialContract {
/// Initialize the contract with an admin address
pub fn initialize(env: Env, admin: Address) {
pub fn initialize(env: Env, admin: Address) -> Result<(), Error> {
admin.require_auth();

if env.storage().instance().has(&DataKey::Admin) {
panic!("Contract already initialized");
return Err(Error::AlreadyInitialized);
}

env.storage().instance().set(&DataKey::Admin, &admin);
Expand All @@ -90,6 +91,8 @@ impl ClinicalTrial {
.instance()
.set(&DataKey::EnrollmentCounter, &0u64);
env.storage().instance().set(&DataKey::EventCounter, &0u64);

Ok(())
}

/// Register a new clinical trial
Expand Down Expand Up @@ -523,9 +526,9 @@ impl ClinicalTrial {

// Generate a hash representing the exported dataset
// In production, this would be a hash of the actual de-identified data
let export_hash = env.crypto().sha256(&export_count.to_be_bytes().into());
let export_hash = env.crypto().sha256(&soroban_sdk::Bytes::from_slice(&env, &export_count.to_be_bytes()));

Ok(export_hash)
Ok(export_hash.into())
}

/// Get trial information
Expand Down
60 changes: 26 additions & 34 deletions contracts/clinical-trial/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::{ClinicalTrialClient, DataFilters, AdverseEvent, CriteriaRule};
use soroban_sdk::{symbol_short, testutils::Address as _, vec, Address, BytesN, Env, String, Vec};
use crate::{ClinicalTrialContractClient, Error};
use soroban_sdk::{symbol_short, testutils::Address as _, Address, BytesN, Env, String};

fn create_test_env() -> (Env, Address, Address, Address, ClinicalTrialClient<'static>) {
fn create_test_env() -> (Env, Address, Address, Address, ClinicalTrialContractClient<'static>) {
let env = Env::default();
env.mock_all_auths();

let admin = Address::generate(&env);
let pi = Address::generate(&env);
let patient = Address::generate(&env);

let contract_id = env.register_contract(None, crate::ClinicalTrial);
let client = ClinicalTrialClient::new(&env, &contract_id);
let contract_id = env.register_contract(None, crate::ClinicalTrialContract);
let client = ClinicalTrialContractClient::new(&env, &contract_id);

client.initialize(&admin);

Expand All @@ -19,25 +19,15 @@ fn create_test_env() -> (Env, Address, Address, Address, ClinicalTrialClient<'st

fn create_protocol_hash(env: &Env) -> BytesN<32> {
let data = String::from_str(env, "protocol_v1");
env.crypto().sha256(&data.into())
}

fn create_consent_hash(env: &Env) -> BytesN<32> {
let data = String::from_str(env, "informed_consent");
env.crypto().sha256(&data.into())
}

fn create_data_hash(env: &Env) -> BytesN<32> {
let data = String::from_str(env, "patient_data");
env.crypto().sha256(&data.into())
env.crypto().sha256(&data.into()).into()
}

#[test]
fn test_initialize() {
let (env, admin, _, _, client) = create_test_env();
// Contract should be initialized successfully
let trial_id = client.register_clinical_trial(

// Successful registration confirms contract is initialized
let trial_record_id = client.register_clinical_trial(
&admin,
&String::from_str(&env, "TRIAL001"),
&String::from_str(&env, "Cancer Treatment Study"),
Expand All @@ -48,29 +38,31 @@ fn test_initialize() {
&100,
&String::from_str(&env, "IRB-2024-001"),
);
assert!(trial_id.is_ok());

assert_eq!(trial_record_id, 0u64);
}

#[test]
#[should_panic(expected = "Contract already initialized")]
fn test_double_initialize() {
let env = Env::default();
env.mock_all_auths();

let admin = Address::generate(&env);
let contract_id = env.register_contract(None, crate::ClinicalTrial);
let client = ClinicalTrialClient::new(&env, &contract_id);
let contract_id = env.register_contract(None, crate::ClinicalTrialContract);
let client = ClinicalTrialContractClient::new(&env, &contract_id);

client.initialize(&admin);
client.initialize(&admin); // Should panic

// Second initialization must return AlreadyInitialized typed error
let result = client.try_initialize(&admin);
assert_eq!(result, Err(Ok(Error::AlreadyInitialized)));
}

#[test]
fn test_register_clinical_trial() {
let (env, _, pi, _, client) = create_test_env();

let trial_id = client.register_clinical_trial(
let trial_record_id = client.register_clinical_trial(
&pi,
&String::from_str(&env, "TRIAL001"),
&String::from_str(&env, "Diabetes Study"),
Expand All @@ -82,13 +74,7 @@ fn test_register_clinical_trial() {
&String::from_str(&env, "IRB-2024-002"),
);

assert!(trial_id.is_ok());
let trial_record_id = trial_id.unwrap();

let trial = client.get_trial(&trial_record_id);
assert!(trial.is_ok());

let trial_data = trial.unwrap();
let trial_data = client.get_trial(&trial_record_id);
assert_eq!(trial_data.trial_record_id, trial_record_id);
assert_eq!(trial_data.principal_investigator, pi);
assert_eq!(trial_data.enrollment_target, 200);
Expand Down Expand Up @@ -124,4 +110,10 @@ fn test_invalid_date_range() {
&symbol_short!("phase1"),
&create_protocol_hash(&env),
&5000,
&1000,
&1000, // end before start
&100,
&String::from_str(&env, "IRB-2024-004"),
);

assert!(result.is_err());
}
Loading