From d0a81b1c486403b30d419e8719d78d334422a795 Mon Sep 17 00:00:00 2001 From: Connor Barr Date: Tue, 19 Mar 2024 10:48:02 +0000 Subject: [PATCH] Basic milliseconds type --- packages/std/src/common/milliseconds.rs | 108 ++++++++++++++++++++++++ packages/std/src/common/mod.rs | 64 ++------------ packages/std/src/common/queries.rs | 14 --- 3 files changed, 114 insertions(+), 72 deletions(-) create mode 100644 packages/std/src/common/milliseconds.rs delete mode 100644 packages/std/src/common/queries.rs diff --git a/packages/std/src/common/milliseconds.rs b/packages/std/src/common/milliseconds.rs new file mode 100644 index 000000000..10c6364ce --- /dev/null +++ b/packages/std/src/common/milliseconds.rs @@ -0,0 +1,108 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{Env, Timestamp}; +use cw20::Expiration; + +#[cw_serde] +/// Represents time in milliseconds. +pub struct Milliseconds(u64); + +impl Milliseconds { + pub fn is_block_expired(&self, env: &Env) -> bool { + let time = env.block.time.seconds() * 1000; + self.0 <= time + } + + #[inline] + pub fn from_seconds(seconds: u64) -> Milliseconds { + if seconds > u64::MAX / 1000 { + panic!("Overflow: Cannot convert seconds to milliseconds") + } + + Milliseconds(seconds * 1000) + } + + #[inline] + pub fn from_nanos(nanos: u64) -> Milliseconds { + Milliseconds(nanos / 1000000) + } + + #[inline] + pub fn seconds(&self) -> u64 { + self.0 / 1000 + } + + #[inline] + pub fn nanos(&self) -> u64 { + if self.0 > u64::MAX / 1000000 { + panic!("Overflow: Cannot convert milliseconds time to nanoseconds") + } + self.0 * 1000000 + } +} + +impl From for String { + fn from(time: Milliseconds) -> String { + time.0.to_string() + } +} + +impl From for Timestamp { + fn from(time: Milliseconds) -> Timestamp { + Timestamp::from_nanos(time.nanos()) + } +} + +impl From for Expiration { + fn from(time: Milliseconds) -> Expiration { + Expiration::AtTime(time.into()) + } +} + +#[cfg(test)] +mod test { + use cosmwasm_std::testing::mock_env; + + use super::*; + + struct IsExpiredTestCase { + name: &'static str, + input: u64, + curr_time: u64, + is_expired: bool, + } + + #[test] + fn test_is_expired() { + let test_cases: Vec = vec![ + IsExpiredTestCase { + name: "valid expiration time (expired)", + input: 0, + curr_time: 1, + is_expired: true, + }, + IsExpiredTestCase { + name: "valid expiration time (not expired)", + input: 1, + curr_time: 0, + is_expired: false, + }, + IsExpiredTestCase { + name: "same time (expired)", + input: 0, + curr_time: 0, + is_expired: true, + }, + ]; + + for test in test_cases { + let input = Milliseconds(test.input); + let curr_time = Milliseconds(test.curr_time); + let mut env = mock_env(); + env.block.time = curr_time.into(); + + let output = input.is_block_expired(&env); + + assert_eq!(test.is_expired, output, "Test failed: {}", test.name) + } + } +} diff --git a/packages/std/src/common/mod.rs b/packages/std/src/common/mod.rs index e58e80e2e..5fb4a5843 100644 --- a/packages/std/src/common/mod.rs +++ b/packages/std/src/common/mod.rs @@ -1,19 +1,20 @@ pub mod context; pub mod expiration; -pub mod queries; +pub mod milliseconds; pub mod rates; pub mod reply; pub mod response; pub mod withdraw; +pub use milliseconds::*; + use crate::error::ContractError; use cosmwasm_std::{ - ensure, from_binary, has_coins, to_binary, BankMsg, Binary, Coin, CosmosMsg, QuerierWrapper, - SubMsg, Uint128, + ensure, has_coins, to_binary, BankMsg, Binary, Coin, CosmosMsg, SubMsg, Uint128, }; use cw20::Cw20Coin; -use serde::{de::DeserializeOwned, Serialize}; +use serde::Serialize; use std::collections::BTreeMap; use cosmwasm_schema::cw_serde; @@ -23,24 +24,6 @@ pub enum OrderBy { Desc, } -pub fn parse_struct(val: &Binary) -> Result -where - T: DeserializeOwned, -{ - let data_res = from_binary(val); - match data_res { - Ok(data) => Ok(data), - Err(err) => Err(ContractError::ParsingError { - err: err.to_string(), - }), - } -} - -pub fn parse_message(data: &Option) -> Result { - let data = unwrap_or_err(data, ContractError::MissingRequiredMessageData {})?; - parse_struct::(data) -} - pub fn encode_binary(val: &T) -> Result where T: Serialize, @@ -51,24 +34,6 @@ where } } -pub fn unwrap_or_err(val_opt: &Option, err: ContractError) -> Result<&T, ContractError> { - match val_opt { - Some(val) => Ok(val), - None => Err(err), - } -} - -pub fn query_primitive( - _querier: QuerierWrapper, - _contract_address: String, - _key: Option, -) -> Result -where - T: DeserializeOwned, -{ - todo!() -} - #[cw_serde] pub enum Funds { Native(Coin), @@ -214,7 +179,7 @@ pub fn deduct_funds(coins: &mut [Coin], funds: &Coin) -> Result<(), ContractErro #[cfg(test)] mod test { - use cosmwasm_std::{coin, to_binary, Uint128, WasmMsg}; + use cosmwasm_std::{coin, Uint128, WasmMsg}; use cw20::Expiration; use super::*; @@ -225,23 +190,6 @@ mod test { expiration: Expiration, } - #[test] - fn test_parse_struct() { - let valid_json = to_binary(&TestStruct { - name: "John Doe".to_string(), - expiration: Expiration::AtHeight(123), - }) - .unwrap(); - - let test_struct: TestStruct = parse_struct(&valid_json).unwrap(); - assert_eq!(test_struct.name, "John Doe"); - assert_eq!(test_struct.expiration, Expiration::AtHeight(123)); - - let invalid_json = to_binary("notavalidteststruct").unwrap(); - - assert!(parse_struct::(&invalid_json).is_err()) - } - #[test] fn test_merge_coins() { let coins = vec![coin(100, "uusd"), coin(100, "uluna")]; diff --git a/packages/std/src/common/queries.rs b/packages/std/src/common/queries.rs deleted file mode 100644 index 22aff90ea..000000000 --- a/packages/std/src/common/queries.rs +++ /dev/null @@ -1,14 +0,0 @@ -use cosmwasm_std::QuerierWrapper; - -use crate::error::ContractError; - -/// Queries contract info for a given address. -/// If the query errors the assumption is that the address is not a contract, if not then the address must be a contract. -/// -/// Returns a result containing a boolean as to whether the given address is a contract or not -pub fn is_contract(querier: QuerierWrapper, addr: &String) -> Result { - match querier.query_wasm_contract_info(addr) { - Ok(_) => Ok(true), - Err(_) => Ok(false), - } -}