diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c625f05..2d05bfa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,6 @@ jobs: uses: stellar-expert/soroban-build-workflow/.github/workflows/release.yml@main with: release_name: ${{ github.ref_name }} - build_path: '[""]' release_description: 'Release of the contract' secrets: release_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 17feaf0..56eaa2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -793,7 +793,7 @@ dependencies = [ [[package]] name = "reflector-oracle" -version = "3.0.0" +version = "4.0.0" dependencies = [ "soroban-sdk", ] diff --git a/Cargo.toml b/Cargo.toml index cd60b81..a024f75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "reflector-oracle" -version = "3.0.0" +version = "4.0.0" edition = "2021" [lib] diff --git a/src/extensions/env_extensions.rs b/src/extensions/env_extensions.rs index 60cd9aa..f139ba1 100644 --- a/src/extensions/env_extensions.rs +++ b/src/extensions/env_extensions.rs @@ -32,7 +32,7 @@ pub trait EnvExtensions { fn set_resolution(&self, resolution: u32); - fn get_retention_period(&self) -> Option; + fn get_retention_period(&self) -> u64; fn set_retention_period(&self, period: u64); @@ -96,7 +96,7 @@ impl EnvExtensions for Env { get_instance_storage(&self).set(&RESOLUTION, &resolution) } - fn get_retention_period(&self) -> Option { + fn get_retention_period(&self) -> u64 { get_instance_storage(&self) .get(&RETENTION_PERIOD) .unwrap_or_default() diff --git a/src/lib.rs b/src/lib.rs index e6775f1..c45a199 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,12 @@ impl PriceOracleContract { // // History retention period (in seconds) pub fn period(e: Env) -> Option { - e.get_retention_period() + let period = e.get_retention_period(); + if period == 0 { + return None; + } else { + return Some(period / 1000); //convert to seconds + } } // Returns all assets quoted by the contract. @@ -61,13 +66,13 @@ impl PriceOracleContract { e.get_assets() } - // Returns the most recent price update timestamp. + // Returns the most recent price update timestamp in seconds. // // # Returns // // Timestamp of the last recorded price update pub fn last_timestamp(e: Env) -> u64 { - e.get_last_timestamp() + e.get_last_timestamp() / 1000 //convert to seconds } // Returns price in base asset at specific timestamp. @@ -75,14 +80,15 @@ impl PriceOracleContract { // # Arguments // // * `asset` - Asset to quote - // * `timestamp` - Timestamp + // * `timestamp` - Timestamp in seconds // // # Returns // // Price record for the given asset at the given timestamp or None if the record was not found pub fn price(e: Env, asset: Asset, timestamp: u64) -> Option { let resolution = e.get_resolution(); - let normalized_timestamp = timestamp.get_normalized_timestamp(resolution.into()); + let normalized_timestamp = //convert to milliseconds and normalize + (timestamp * 1000).get_normalized_timestamp(resolution.into()); //get the price get_price_data(&e, asset, normalized_timestamp) } @@ -164,7 +170,8 @@ impl PriceOracleContract { quote_asset: Asset, timestamp: u64, ) -> Option { - let normalized_timestamp = timestamp.get_normalized_timestamp(e.get_resolution().into()); + let normalized_timestamp = //convert to milliseconds and normalize + (timestamp * 1000).get_normalized_timestamp(e.get_resolution().into()); let decimals = e.get_decimals(); get_x_price(&e, base_asset, quote_asset, normalized_timestamp, decimals) } @@ -367,7 +374,7 @@ impl PriceOracleContract { panic_with_error!(&e, Error::InvalidTimestamp); } - let retention_period = e.get_retention_period().unwrap(); + let retention_period = e.get_retention_period(); let ledgers_to_live: u32 = ((retention_period / 1000 / 5) + 1) as u32; @@ -488,7 +495,7 @@ fn get_twap Option>( return None; } - let last_price_timestamp = prices.first()?.timestamp; + let last_price_timestamp = prices.first()?.timestamp * 1000; //convert to milliseconds to match the timestamp format let timeframe = e.get_resolution() as u64; let current_time = now(&e); @@ -524,10 +531,7 @@ fn get_x_price_by_indexes( let (base_asset, quote_asset) = asset_pair_indexes; //check if the asset are the same if base_asset == quote_asset { - return Some(PriceData { - price: 10i128.pow(decimals), - timestamp, - }); + return Some(get_normalized_price_data(10i128.pow(decimals), timestamp)); } //get the price for base_asset @@ -543,12 +547,12 @@ fn get_x_price_by_indexes( } //calculate the cross price - Some(PriceData { - price: base_asset_price + Some(get_normalized_price_data( + base_asset_price .unwrap() .fixed_div_floor(quote_asset_price.unwrap(), decimals), timestamp, - }) + )) } fn get_asset_pair_indexes(e: &Env, base_asset: Asset, quote_asset: Asset) -> Option<(u8, u8)> { @@ -578,8 +582,12 @@ fn get_price_data_by_index(e: &Env, asset: u8, timestamp: u64) -> Option PriceData { + PriceData { + price, + timestamp: timestamp / 1000, //convert to seconds + } } diff --git a/src/test.rs b/src/test.rs index a833633..1505ffc 100644 --- a/src/test.rs +++ b/src/test.rs @@ -15,6 +15,10 @@ use {extensions::i128_extensions::I128Extensions, types::asset::Asset}; const RESOLUTION: u32 = 300_000; const DECIMALS: u32 = 14; +fn convert_to_seconds(timestamp: u64) -> u64 { + timestamp / 1000 +} + fn init_contract_with_admin<'a>() -> (Env, PriceOracleContractClient<'a>, ConfigData) { let env = Env::default(); @@ -85,8 +89,13 @@ fn get_updates(env: &Env, assets: &Vec, price: i128) -> Vec { fn version_test() { let (_env, client, _init_data) = init_contract_with_admin(); let result = client.version(); - - assert_eq!(result, 3); + let version = env!("CARGO_PKG_VERSION") + .split(".") + .next() + .unwrap() + .parse::() + .unwrap(); + assert_eq!(result, version); } #[test] @@ -103,7 +112,7 @@ fn init_test() { assert_eq!(resolution, RESOLUTION / 1000); let period = client.period().unwrap(); - assert_eq!(period, init_data.period); + assert_eq!(period, init_data.period / 1000); let decimals = client.decimals(); assert_eq!(decimals, DECIMALS); @@ -209,7 +218,7 @@ fn last_price_test() { result, Some(PriceData { price: normalize_price(200), - timestamp: 900_000 as u64 + timestamp: convert_to_seconds(900_000) }) ); } @@ -234,7 +243,7 @@ fn last_timestamp_test() { result = client.last_timestamp(); - assert_eq!(result, 600_000); + assert_eq!(result, convert_to_seconds(600_000)); } #[test] @@ -320,7 +329,7 @@ fn set_period_test() { let result = client.period().unwrap(); - assert_eq!(result, period); + assert_eq!(result, convert_to_seconds(period)); } #[test] @@ -348,18 +357,18 @@ fn get_price_test() { result, Some(PriceData { price: normalize_price(200), - timestamp: 900_000 as u64 + timestamp: convert_to_seconds(900_000) }) ); //check price at 899_000 - result = client.price(&assets.get_unchecked(1), &899_000); + result = client.price(&assets.get_unchecked(1), &convert_to_seconds(899_000)); assert_ne!(result, None); assert_eq!( result, Some(PriceData { price: normalize_price(100), - timestamp: 600_000 as u64 + timestamp: convert_to_seconds(600_000) }) ); } @@ -402,7 +411,7 @@ fn get_x_last_price_test() { result, Some(PriceData { price: normalize_price(1), - timestamp: 600_000 as u64 + timestamp: convert_to_seconds(600_000) }) ); } @@ -422,7 +431,11 @@ fn get_x_price_with_zero_test() { //set prices for assets client.set_price(&updates, ×tamp); - let result = client.x_price(&assets.get(0).unwrap(), &assets.get(1).unwrap(), ×tamp); + let result = client.x_price( + &assets.get(0).unwrap(), + &assets.get(1).unwrap(), + &convert_to_seconds(timestamp), + ); assert_eq!(result, None); } @@ -454,18 +467,22 @@ fn get_x_price_test() { result, Some(PriceData { price: normalize_price(1), - timestamp: 900_000 as u64 + timestamp: convert_to_seconds(900_000) }) ); //check price at 899_000 - result = client.x_price(&assets.get_unchecked(1), &assets.get_unchecked(2), &899_000); + result = client.x_price( + &assets.get_unchecked(1), + &assets.get_unchecked(2), + &convert_to_seconds(899_000), + ); assert_ne!(result, None); assert_eq!( result, Some(PriceData { price: normalize_price(1), - timestamp: 600_000 as u64 + timestamp: convert_to_seconds(600_000) }) ); } @@ -589,7 +606,10 @@ fn get_non_registered_asset_price_test() { fn get_asset_price_for_invalid_timestamp_test() { let (env, client, config_data) = init_contract_with_admin(); - let mut result = client.price(&config_data.assets.get_unchecked(1), &u64::MAX); + let mut result = client.price( + &config_data.assets.get_unchecked(1), + &convert_to_seconds(u64::MAX), + ); assert_eq!(result, None); //try to get price for unknown asset