Skip to content
Open
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
21 changes: 21 additions & 0 deletions contracts/price-oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,27 @@ impl PriceOracle {
prices.keys()
}

/// Store a human-readable description for an asset (e.g. "Nigerian Naira").
///
/// Only the admin can call this.
pub fn set_asset_description(env: Env, admin: Address, asset: Symbol, description: soroban_sdk::String) {
admin.require_auth();
crate::auth::_require_authorized(&env, &admin);
env.storage()
.persistent()
.set(&DataKey::AssetDescription(asset), &description);
}

/// Get the human-readable description for an asset.
///
/// Returns `Error::AssetNotFound` if no description has been set.
pub fn get_asset_description(env: Env, asset: Symbol) -> Result<soroban_sdk::String, Error> {
env.storage()
.persistent()
.get(&DataKey::AssetDescription(asset))
.ok_or(Error::AssetNotFound)
}

/// Set the price data for a specific asset.
///
/// # Arguments
Expand Down
82 changes: 82 additions & 0 deletions contracts/price-oracle/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,3 +809,85 @@ fn test_get_prices_empty_input_returns_empty_vec() {

assert_eq!(results.len(), 0);
}

// ============================================================================
// Asset Description Tests
// ============================================================================

#[test]
fn test_set_and_get_asset_description() {
let env = Env::default();
env.mock_all_auths();

let contract_id = env.register(PriceOracle, ());
let client = PriceOracleClient::new(&env, &contract_id);
let admin = <soroban_sdk::Address as soroban_sdk::testutils::Address>::generate(&env);

env.as_contract(&contract_id, || {
crate::auth::_set_admin(&env, &soroban_sdk::vec![&env, admin.clone()]);
});

let asset = symbol_short!("NGN");
let description = soroban_sdk::String::from_str(&env, "Nigerian Naira");

client.set_asset_description(&admin, &asset, &description);

let result = client.get_asset_description(&asset);
assert_eq!(result, description);
}

#[test]
fn test_get_asset_description_not_found_returns_error() {
let env = Env::default();
let contract_id = env.register(PriceOracle, ());
let client = PriceOracleClient::new(&env, &contract_id);

let result = client.try_get_asset_description(&symbol_short!("KES"));
match result {
Err(Ok(e)) => assert_eq!(e, Error::AssetNotFound),
other => panic!("expected AssetNotFound, got {:?}", other),
}
}

#[test]
fn test_set_asset_description_non_admin_rejected() {
let env = Env::default();
env.mock_all_auths();

let contract_id = env.register(PriceOracle, ());
let client = PriceOracleClient::new(&env, &contract_id);
let admin = <soroban_sdk::Address as soroban_sdk::testutils::Address>::generate(&env);
let non_admin = <soroban_sdk::Address as soroban_sdk::testutils::Address>::generate(&env);

env.as_contract(&contract_id, || {
crate::auth::_set_admin(&env, &soroban_sdk::vec![&env, admin.clone()]);
});

let result = client.try_set_asset_description(
&non_admin,
&symbol_short!("NGN"),
&soroban_sdk::String::from_str(&env, "Nigerian Naira"),
);
assert!(result.is_err());
}

#[test]
fn test_set_asset_description_can_be_updated() {
let env = Env::default();
env.mock_all_auths();

let contract_id = env.register(PriceOracle, ());
let client = PriceOracleClient::new(&env, &contract_id);
let admin = <soroban_sdk::Address as soroban_sdk::testutils::Address>::generate(&env);

env.as_contract(&contract_id, || {
crate::auth::_set_admin(&env, &soroban_sdk::vec![&env, admin.clone()]);
});

let asset = symbol_short!("GHS");
client.set_asset_description(&admin, &asset, &soroban_sdk::String::from_str(&env, "Ghanaian Cedi"));
client.set_asset_description(&admin, &asset, &soroban_sdk::String::from_str(&env, "Ghana Cedi"));

let result = client.get_asset_description(&asset);
assert_eq!(result, soroban_sdk::String::from_str(&env, "Ghana Cedi"));
}
3 changes: 2 additions & 1 deletion contracts/price-oracle/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use soroban_sdk::{contracttype, Address};
use soroban_sdk::{contracttype, Address, Symbol};

/// Storage keys for contract data
#[contracttype]
pub enum DataKey {
Admin,
BaseCurrencyPairs,
PriceData,
AssetDescription(Symbol),
}

/// Canonical storage format for a price entry.
Expand Down