diff --git a/contracts/aid-contract/src/lib.rs b/contracts/aid-contract/src/lib.rs index 337d151..ce9df6d 100644 --- a/contracts/aid-contract/src/lib.rs +++ b/contracts/aid-contract/src/lib.rs @@ -1,4 +1,15 @@ #![no_std] + 7-aid-initialization +use soroban_sdk::{ + contract, contractimpl, contracterror, panic_with_error, token, symbol_short, Address, Env, Symbol, Map, +}; +use shared::events::{emit_aid_created, emit_action_executed, emit_module_initialized, emit_permission_changed}; +use shared::{emit, AID_CLAIMED, AID_CREATED, AID_REFUNDED, AID_SETTLED, Error}; +use shared::storage::is_paused; + +const KEY_AIDS: Symbol = symbol_short!("aids"); + + main use shared::events::{ emit_action_executed, emit_aid_created, emit_module_initialized, emit_permission_changed, @@ -50,11 +61,42 @@ impl AidContract { // Lifecycle // ----------------------------------------------------------------------- - /// Initialise the contract with an admin and the escrow token. + /// Initialize the contract with configuration. /// /// Must be called exactly once immediately after deployment. - pub fn initialize(env: Env, admin: Address, token: Address) { + /// + /// # Arguments + /// * `admin` - The admin address with governance privileges. + /// * `treasury` - The treasury address for fees or emergency withdrawals. + /// * `token` - The accepted escrow token address. + /// * `default_expiry_secs` - Default expiration time in seconds for new aids. + /// + /// # Errors + /// * [`shared::Error::AlreadyInitialized`] - If called more than once. + pub fn initialize( + env: Env, + admin: Address, + treasury: Address, + token: Address, + default_expiry_secs: u64, + ) -> Result<(), shared::Error> { + // Guard against re-initialization + if storage::is_initialized(&env) { + return Err(shared::Error::AlreadyInitialized); + } + + admin.require_auth(); + + // Store configuration shared::auth::set_admin(&env, &admin); + 7-aid-initialization + storage::set_treasury(&env, &treasury); + storage::set_token(&env, &token); + storage::set_default_expiry(&env, default_expiry_secs); + storage::set_initialized(&env); + + + main emit_module_initialized( &env, symbol_short!("aid"), @@ -62,9 +104,74 @@ impl AidContract { &admin, env.ledger().timestamp(), ); + 7-aid-initialization + + Ok(()) + } + + /// Get the admin address. + pub fn get_admin(env: Env) -> Address { + shared::auth::get_admin(&env) + } + + /// Get the treasury address. + pub fn get_treasury(env: Env) -> Option
{ + storage::get_treasury(&env) + } + + /// Get the escrow token address. + pub fn get_token(env: Env) -> Option
{ + storage::get_token(&env) + } + + /// Get the default expiry in seconds. + pub fn get_default_expiry(env: Env) -> Option { + storage::get_default_expiry(&env) + } + + /// Check if the contract is initialized. + pub fn is_initialized(env: Env) -> bool { + storage::is_initialized(&env) + } + + /// Update configuration (admin only). + /// + /// # Arguments + /// * `admin` - Must be the current admin. + /// * `treasury` - New treasury address (None = keep existing). + /// * `default_expiry_secs` - New default expiry (None = keep existing). + /// + /// # Errors + /// * [`shared::Error::Unauthorized`] - If caller is not admin. + pub fn update_config( + env: Env, + admin: Address, + treasury: Option
, + default_expiry_secs: Option, + ) -> Result<(), shared::Error> { + // Verify admin authorization + let current_admin = shared::auth::get_admin(&env); + if admin != current_admin { + return Err(shared::Error::Unauthorized); + } + admin.require_auth(); + + // Update treasury if provided + if let Some(t) = treasury { + storage::set_treasury(&env, &t); + } + + // Update default expiry if provided + if let Some(e) = default_expiry_secs { + storage::set_default_expiry(&env, e); + } + + Ok(()) + env.storage() .instance() .set(&storage::DataKey::Token, &token); + main } // ----------------------------------------------------------------------- diff --git a/contracts/aid-contract/src/storage.rs b/contracts/aid-contract/src/storage.rs index 0c161ba..12da077 100644 --- a/contracts/aid-contract/src/storage.rs +++ b/contracts/aid-contract/src/storage.rs @@ -37,6 +37,12 @@ pub enum DataKey { AidCounter, /// Token address escrowed by this contract (instance). Token, + /// Treasury address (instance). + Treasury, + /// Default expiry in seconds (instance). + DefaultExpiry, + /// Configuration marker (instance) - set on initialize. + Initialized, /// Append-only list of aid IDs created by a donor (persistent). DonorIndex(Address), /// Append-only list of aid IDs assigned to a recipient (persistent). @@ -139,4 +145,46 @@ pub fn append_recipient_index(env: &Env, recipient: &Address, aid_id: u64) { let mut ids = get_recipient_index(env, recipient); ids.push_back(aid_id); persistent_set(env, &DataKey::RecipientIndex(recipient.clone()), &ids); + + +// --------------------------------------------------------------------------- +// Treasury address — instance storage +// --------------------------------------------------------------------------- + +/// Read the configured treasury address, if initialised. +pub fn get_treasury(env: &Env) -> Option
{ + instance_get(env, &DataKey::Treasury) +} + +/// Store the treasury address (initialisation only). +pub fn set_treasury(env: &Env, treasury: &Address) { + instance_set(env, &DataKey::Treasury, treasury); +} + +// --------------------------------------------------------------------------- +// Default expiry — instance storage +// --------------------------------------------------------------------------- + +/// Read the default expiry in seconds, if set. +pub fn get_default_expiry(env: &Env) -> Option { + instance_get(env, &DataKey::DefaultExpiry) +} + +/// Store the default expiry in seconds. +pub fn set_default_expiry(env: &Env, expiry_secs: u64) { + instance_set(env, &DataKey::DefaultExpiry, &expiry_secs); +} + +// --------------------------------------------------------------------------- +// Initialization flag — instance storage +// --------------------------------------------------------------------------- + +/// Check if the contract has been initialized. +pub fn is_initialized(env: &Env) -> bool { + instance_get::(env, &DataKey::Initialized).unwrap_or(false) } + +/// Mark the contract as initialized. +pub fn set_initialized(env: &Env) { + instance_set(env, &DataKey::Initialized, &true); +}} diff --git a/contracts/aid-contract/src/types.rs b/contracts/aid-contract/src/types.rs index 4ef3bfe..30e9090 100644 --- a/contracts/aid-contract/src/types.rs +++ b/contracts/aid-contract/src/types.rs @@ -1,5 +1,16 @@ use soroban_sdk::{contracttype, Address, Vec}; + +/// Contract configuration stored in instance storage. +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Config { + pub admin: Address, + pub treasury: Address, + pub token: Address, + pub default_expiry_secs: u64, +} + /// Lifecycle state of an aid record. #[contracttype] #[derive(Clone, Copy, Debug, Eq, PartialEq)]