Skip to content

refactor(rwa-oracle): remove unused last_timestamp field from RWAOracleStorage #32

Description

@aguilar1x

Description

RWAOracleStorage contains a last_timestamp: u64 field that is written on every set_asset_price call but is never read by any public or private function in the contract.

Current state (storage.rs:17, contract.rs:315-318):

```rust
pub struct RWAOracleStorage {
pub assets: Vec,
pub base: Asset,
pub decimals: u32,
pub resolution: u32,
pub last_timestamp: u64, // ← written but never read
pub rwa_metadata: Map<Symbol, RWAMetadata>,
pub asset_types: Map<Asset, RWAAssetType>,
pub max_staleness: u64,
}

// In set_asset_price_internal — the only usage:
let mut state = RWAOracleStorage::get(env);
state.last_timestamp = timestamp; // ← only write, no reads anywhere
RWAOracleStorage::set(env, &state);
```

No function in the contract reads state.last_timestamp. The per-asset last timestamp is retrieved correctly via IsSep40::lastprice() which reads from persistent storage (DataKey::Prices), not from this field.

Why this is a problem:

  • Every set_asset_price call reads the full RWAOracleStorage struct from instance storage, updates last_timestamp, and writes it back — a wasted read + write for an unused value
  • Instance storage has size limits; removing a field reduces the storage footprint for every deployed oracle
  • The field misleads readers into thinking there is a meaningful global "last updated" concept, when the actual per-asset timestamp lives in DataKey::Prices

Requirements

  • Remove last_timestamp: u64 from RWAOracleStorage
  • Remove the last_timestamp assignment in set_asset_price_internal
  • Remove the entire second RWAOracleStorage::get / RWAOracleStorage::set block from set_asset_price_internal — it only existed to update this field
  • Update RWAOracleStorage::new to not initialize the field
  • Write unit tests for the cases listed below

Acceptance Criteria

  • last_timestamp field removed from RWAOracleStorage struct
  • RWAOracleStorage::new no longer sets last_timestamp
  • set_asset_price_internal no longer reads/writes RWAOracleStorage for the timestamp update
  • set_asset_price still correctly stores prices in persistent storage
  • lastprice() still returns the correct latest price after the refactor
  • All 2 required tests pass
  • All existing tests still pass

Files to Change

  • stellar-contracts/rwa-oracle/src/common/storage.rs — remove field from struct and new()
  • stellar-contracts/rwa-oracle/src/contract.rs — remove update block in set_asset_price_internal

Required Tests

Test Name Scenario Expected Result
test_lastprice_correct_after_multiple_updates Set 3 prices at t1, t2, t3 for the same asset lastprice() returns price at t3
test_lastprice_independent_per_asset Set price for NVDA at t1, TSLA at t2 Each lastprice() returns its own latest

Test structure hint:

```rust
#[test]
fn test_lastprice_correct_after_multiple_updates() {
let e = Env::default();
e.mock_all_auths();
set_ledger_timestamp(&e, 2_000_000_000);
let oracle = create_rwa_oracle_contract(&e);
let asset = Asset::Other(Symbol::new(&e, "NVDA"));

oracle.set_asset_price(&asset, &100, &2_000_000_001);
oracle.set_asset_price(&asset, &200, &2_000_000_002);
oracle.set_asset_price(&asset, &300, &2_000_000_003);

let latest = oracle.lastprice(&asset).unwrap();
assert_eq!(latest.price, 300);
assert_eq!(latest.timestamp, 2_000_000_003);

}

#[test]
fn test_lastprice_independent_per_asset() {
let e = Env::default();
e.mock_all_auths();
set_ledger_timestamp(&e, 2_000_000_000);
let oracle = create_rwa_oracle_contract(&e);
let nvda = Asset::Other(Symbol::new(&e, "NVDA"));
let tsla = Asset::Other(Symbol::new(&e, "TSLA"));

oracle.set_asset_price(&nvda, &500, &2_000_000_001);
oracle.set_asset_price(&tsla, &999, &2_000_000_002);

assert_eq!(oracle.lastprice(&nvda).unwrap().price, 500);
assert_eq!(oracle.lastprice(&tsla).unwrap().price, 999);

}
```

Implementation Hint

```rust
// storage.rs — remove field and initialization:
pub struct RWAOracleStorage {
pub assets: Vec,
pub base: Asset,
pub decimals: u32,
pub resolution: u32,
// remove: pub last_timestamp: u64,
pub rwa_metadata: Map<Symbol, RWAMetadata>,
pub asset_types: Map<Asset, RWAAssetType>,
pub max_staleness: u64,
}

// contract.rs — remove from set_asset_price_internal:
fn set_asset_price_internal(env: &Env, asset_id: Asset, price: i128, timestamp: u64) {
// ... validation and persistent storage unchanged ...

// REMOVE these 4 lines:
// let mut state = RWAOracleStorage::get(env);
// state.last_timestamp = timestamp;
// RWAOracleStorage::set(env, &state);

Admin::extend_instance_ttl(env);
Self::extend_persistent_ttl(env, &DataKey::Prices(asset_id));

}
```

Verification

```bash
cd stellar-contracts
cargo test --package rwa-oracle
cargo build --package rwa-oracle --target wasm32v1-none --release
```

Thank you for taking this issue! You are helping us make RWAs consumer friendly on Stellar.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions