From c1472453a2dd40306e6db37a914580ff8081f1d7 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Sun, 28 Sep 2025 15:39:43 +0100 Subject: [PATCH 1/3] Implement Error Handling Module --- contracts/assetsup_contract/src/error.rs | 55 ++++++++++++++ contracts/assetsup_contract/src/lib.rs | 21 +++-- .../assetsup_contract/src/tests/initialize.rs | 9 ++- .../initialize/test_admin_doesnt_exist.1.json | 76 +++++++++++++++++++ 4 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 contracts/assetsup_contract/src/error.rs create mode 100644 contracts/assetsup_contract/test_snapshots/tests/initialize/test_admin_doesnt_exist.1.json diff --git a/contracts/assetsup_contract/src/error.rs b/contracts/assetsup_contract/src/error.rs new file mode 100644 index 0000000..05ee23d --- /dev/null +++ b/contracts/assetsup_contract/src/error.rs @@ -0,0 +1,55 @@ +use soroban_sdk::{contracterror, panic_with_error, Env}; + +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] +pub enum Error { + AlreadyInitialized = 1, + AdminNotFound = 2, + // Asset exist + AssetAlreadyExists = 3, + //Asset not found + AssetNotFound = 4, + // Branch already exists + BranchAlreadyExists = 5, + // Branch not found + BranchNotFound = 6, + // Subscription already exist + SubscriptionAlreadyExists = 7, + // User not authorized + Unauthorized = 8, + // Payment is not valid + InvalidPayment = 9 +} + +pub fn handle_error(env: &Env, error: Error) -> ! { + panic_with_error!(env, error); +} + +pub fn dummy_function(_env: Env, asset_exists: bool) -> Result<(), Error> { + if asset_exists { + Err(Error::AssetAlreadyExists) + } else { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use soroban_sdk::{Env}; + + #[test] + fn test_dummy_function_asset_exists() { + let env = Env::default(); + let result = dummy_function(env.clone(), true); + assert_eq!(result, Err(Error::AssetAlreadyExists)); + } + + #[test] + fn test_dummy_function_asset_not_exists() { + let env = Env::default(); + let result = dummy_function(env.clone(), false); + assert_eq!(result, Ok(())); + } +} \ No newline at end of file diff --git a/contracts/assetsup_contract/src/lib.rs b/contracts/assetsup_contract/src/lib.rs index a27f944..43caf2a 100644 --- a/contracts/assetsup_contract/src/lib.rs +++ b/contracts/assetsup_contract/src/lib.rs @@ -1,5 +1,8 @@ #![no_std] +mod error; + use soroban_sdk::{contract, contracttype, contractimpl, Address, Env}; +use crate::error::{Error, handle_error}; #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] @@ -12,17 +15,25 @@ pub struct AssetUpContract; #[contractimpl] impl AssetUpContract { - pub fn initialize(env: Env, admin: Address){ + pub fn initialize(env: Env, admin: Address) -> Result<(), Error>{ admin.require_auth(); if env.storage().persistent().has(&DataKey::Admin) { - panic!("Contract is already initialized"); + handle_error(&env, Error::AlreadyInitialized) + } - env.storage().persistent().set(&DataKey::Admin, &admin); + Ok(env.storage().persistent().set(&DataKey::Admin, &admin)) } - pub fn get_admin(env: Env) -> Address { - env.storage().persistent().get(&DataKey::Admin).unwrap() + pub fn get_admin(env: Env) -> Result { + let key = DataKey::Admin; + if !env.storage().persistent().has(&key) { + handle_error(&env, Error::AdminNotFound) + } + + let admin = env.storage().persistent().get(&key).unwrap(); + Ok(admin) + } } diff --git a/contracts/assetsup_contract/src/tests/initialize.rs b/contracts/assetsup_contract/src/tests/initialize.rs index 11500f3..ea17cf7 100644 --- a/contracts/assetsup_contract/src/tests/initialize.rs +++ b/contracts/assetsup_contract/src/tests/initialize.rs @@ -30,9 +30,16 @@ fn test_initialize() { #[test] -#[should_panic()] +#[should_panic(expected = "Error(Contract, #1)")] fn test_initialize_panic() { let (_env, client, admin) = setup_test_environment(); client.initialize(&admin); client.initialize(&admin); +} + +#[test] +#[should_panic(expected = "Error(Contract, #2)")] +fn test_admin_doesnt_exist() { + let (_env, client, _) = setup_test_environment(); + client.get_admin(); } \ No newline at end of file diff --git a/contracts/assetsup_contract/test_snapshots/tests/initialize/test_admin_doesnt_exist.1.json b/contracts/assetsup_contract/test_snapshots/tests/initialize/test_admin_doesnt_exist.1.json new file mode 100644 index 0000000..5655749 --- /dev/null +++ b/contracts/assetsup_contract/test_snapshots/tests/initialize/test_admin_doesnt_exist.1.json @@ -0,0 +1,76 @@ +{ + "generators": { + "address": 2, + "nonce": 0 + }, + "auth": [ + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file From f7ece8f3d4cdabf21f67b6fc85c272594b9a9e28 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Fri, 3 Oct 2025 10:34:15 +0100 Subject: [PATCH 2/3] fix error module --- contracts/assetsup/src/errors.rs | 8 -------- contracts/assetsup/src/lib.rs | 11 ++++++----- .../asset/test_register_and_get_asset_success.1.json | 4 ++-- .../tests/asset/test_register_asset_duplicate.1.json | 4 ++-- 4 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 contracts/assetsup/src/errors.rs diff --git a/contracts/assetsup/src/errors.rs b/contracts/assetsup/src/errors.rs deleted file mode 100644 index c872c70..0000000 --- a/contracts/assetsup/src/errors.rs +++ /dev/null @@ -1,8 +0,0 @@ -use soroban_sdk::contracterror; - -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ContractError { - AssetAlreadyExists = 1, - AssetNotFound = 2, -} diff --git a/contracts/assetsup/src/lib.rs b/contracts/assetsup/src/lib.rs index 28e2e56..62eee69 100644 --- a/contracts/assetsup/src/lib.rs +++ b/contracts/assetsup/src/lib.rs @@ -1,10 +1,11 @@ #![no_std] + use crate::error::{Error, handle_error}; use soroban_sdk::{Address, BytesN, Env, contract, contractimpl, contracttype}; pub(crate) mod asset; -pub(crate) mod errors; pub(crate) mod types; +pub(crate) mod error; pub use types::*; @@ -41,7 +42,7 @@ impl AssetUpContract { } // Asset functions - pub fn register_asset(env: Env, asset: asset::Asset) -> Result<(), errors::ContractError> { + pub fn register_asset(env: Env, asset: asset::Asset) -> Result<(), Error> { // Access control asset.owner.require_auth(); @@ -52,7 +53,7 @@ impl AssetUpContract { let key = asset::DataKey::Asset(asset.id.clone()); let store = env.storage().persistent(); if store.has(&key) { - return Err(errors::ContractError::AssetAlreadyExists); + return Err(Error::AssetAlreadyExists); } store.set(&key, &asset); Ok(()) @@ -61,12 +62,12 @@ impl AssetUpContract { pub fn get_asset( env: Env, asset_id: BytesN<32>, - ) -> Result { + ) -> Result { let key = asset::DataKey::Asset(asset_id); let store = env.storage().persistent(); match store.get::<_, asset::Asset>(&key) { Some(a) => Ok(a), - None => Err(errors::ContractError::AssetNotFound), + None => Err(Error::AssetNotFound), } } } diff --git a/contracts/assetsup/test_snapshots/tests/asset/test_register_and_get_asset_success.1.json b/contracts/assetsup/test_snapshots/tests/asset/test_register_and_get_asset_success.1.json index 1d4890f..b10000c 100644 --- a/contracts/assetsup/test_snapshots/tests/asset/test_register_and_get_asset_success.1.json +++ b/contracts/assetsup/test_snapshots/tests/asset/test_register_and_get_asset_success.1.json @@ -23,7 +23,7 @@ "val": { "vec": [ { - "symbol": "IT" + "symbol": "Digital" } ] } @@ -199,7 +199,7 @@ "val": { "vec": [ { - "symbol": "IT" + "symbol": "Digital" } ] } diff --git a/contracts/assetsup/test_snapshots/tests/asset/test_register_asset_duplicate.1.json b/contracts/assetsup/test_snapshots/tests/asset/test_register_asset_duplicate.1.json index 591423c..bf7f439 100644 --- a/contracts/assetsup/test_snapshots/tests/asset/test_register_asset_duplicate.1.json +++ b/contracts/assetsup/test_snapshots/tests/asset/test_register_asset_duplicate.1.json @@ -23,7 +23,7 @@ "val": { "vec": [ { - "symbol": "Furniture" + "symbol": "Physical" } ] } @@ -199,7 +199,7 @@ "val": { "vec": [ { - "symbol": "Furniture" + "symbol": "Physical" } ] } From 75fa0d5af22861e8e22b613929b2a15394e1432b Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Fri, 3 Oct 2025 10:53:03 +0100 Subject: [PATCH 3/3] format and linting --- contracts/assetsup/src/error.rs | 9 +++++---- contracts/assetsup/src/lib.rs | 14 +++++--------- contracts/assetsup/src/tests/initialize.rs | 1 - 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/contracts/assetsup/src/error.rs b/contracts/assetsup/src/error.rs index 05ee23d..42fa4e3 100644 --- a/contracts/assetsup/src/error.rs +++ b/contracts/assetsup/src/error.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{contracterror, panic_with_error, Env}; +use soroban_sdk::{Env, contracterror, panic_with_error}; #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -19,13 +19,14 @@ pub enum Error { // User not authorized Unauthorized = 8, // Payment is not valid - InvalidPayment = 9 + InvalidPayment = 9, } pub fn handle_error(env: &Env, error: Error) -> ! { panic_with_error!(env, error); } +#[allow(dead_code)] pub fn dummy_function(_env: Env, asset_exists: bool) -> Result<(), Error> { if asset_exists { Err(Error::AssetAlreadyExists) @@ -37,7 +38,7 @@ pub fn dummy_function(_env: Env, asset_exists: bool) -> Result<(), Error> { #[cfg(test)] mod tests { use super::*; - use soroban_sdk::{Env}; + use soroban_sdk::Env; #[test] fn test_dummy_function_asset_exists() { @@ -52,4 +53,4 @@ mod tests { let result = dummy_function(env.clone(), false); assert_eq!(result, Ok(())); } -} \ No newline at end of file +} diff --git a/contracts/assetsup/src/lib.rs b/contracts/assetsup/src/lib.rs index 62eee69..7957963 100644 --- a/contracts/assetsup/src/lib.rs +++ b/contracts/assetsup/src/lib.rs @@ -4,8 +4,8 @@ use crate::error::{Error, handle_error}; use soroban_sdk::{Address, BytesN, Env, contract, contractimpl, contracttype}; pub(crate) mod asset; -pub(crate) mod types; pub(crate) mod error; +pub(crate) mod types; pub use types::*; @@ -20,14 +20,14 @@ pub struct AssetUpContract; #[contractimpl] impl AssetUpContract { - pub fn initialize(env: Env, admin: Address) -> Result<(), Error>{ + pub fn initialize(env: Env, admin: Address) -> Result<(), Error> { admin.require_auth(); if env.storage().persistent().has(&DataKey::Admin) { handle_error(&env, Error::AlreadyInitialized) - } - Ok(env.storage().persistent().set(&DataKey::Admin, &admin)) + env.storage().persistent().set(&DataKey::Admin, &admin); + Ok(()) } pub fn get_admin(env: Env) -> Result { @@ -38,7 +38,6 @@ impl AssetUpContract { let admin = env.storage().persistent().get(&key).unwrap(); Ok(admin) - } // Asset functions @@ -59,10 +58,7 @@ impl AssetUpContract { Ok(()) } - pub fn get_asset( - env: Env, - asset_id: BytesN<32>, - ) -> Result { + pub fn get_asset(env: Env, asset_id: BytesN<32>) -> Result { let key = asset::DataKey::Asset(asset_id); let store = env.storage().persistent(); match store.get::<_, asset::Asset>(&key) { diff --git a/contracts/assetsup/src/tests/initialize.rs b/contracts/assetsup/src/tests/initialize.rs index fe71135..05e596d 100644 --- a/contracts/assetsup/src/tests/initialize.rs +++ b/contracts/assetsup/src/tests/initialize.rs @@ -29,7 +29,6 @@ fn test_initialize() { #[test] #[should_panic(expected = "Error(Contract, #1)")] -#[should_panic] fn test_initialize_panic() { let (_env, client, admin) = setup_test_environment(); client.initialize(&admin);