Skip to content

Commit

Permalink
wip: oracle contract feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
emidev98 committed Jun 16, 2023
1 parent 2ae74b5 commit 22c0739
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 67 deletions.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,22 @@ $ cargo make build
Optimize the built code
```sh
$ cargo make optimize
```
```

## Deployment

Before executing the following scripts, navigate to the scripts folder and execute `yarn` command to install the dependencies for the set of scripts. Also remember to set the following environment variables:

```sh
# Mnemonic of the account to deploy the contract with
MNEMONIC=
# Chain id where to deploy the contract
CHAIN_ID=
# Prefix of the acccounts where to deploy the smart contract
ACC_PREFIX=
```

To deploy the oracle smart contract it can be done by executing the following command:
```sh
$ cargo make deploy-oracle
```
83 changes: 54 additions & 29 deletions contracts/alliance-oracle/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use std::env;

use alliance_protocol::alliance_oracle_types::{
ChainId, ChainInfo, ChainInfoMsg, ExecuteMsg, InstantiateMsg, QueryMsg,
ChainId, ChainInfo, ChainsInfo, Config, ExecuteMsg, InstantiateMsg, QueryMsg,
Expire
};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Order, Response, StdResult,
to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Order, Response, StdError, StdResult,
};
use cw2::set_contract_version;

use crate::error::ContractError;
use crate::state::{Config, CHAINS_INFO, CONFIG};
use crate::state::{CHAINS_INFO, CONFIG, LUNA_INFO};
use crate::utils;

// version info for migration info
Expand All @@ -30,13 +33,15 @@ pub fn instantiate(
CONFIG.save(
deps.storage,
&Config {
data_expiry_seconds: msg.data_expiry_seconds,
governance_addr,
controller_addr,
},
)?;

Ok(Response::new()
.add_attribute("action", "instantiate")
.add_attribute("data_expiry_seconds", msg.data_expiry_seconds.to_string())
.add_attribute("controller_addr", msg.controller_addr)
.add_attribute("governance_addr", msg.governance_addr))
}
Expand All @@ -59,49 +64,69 @@ fn update_chains_info(
deps: DepsMut,
env: Env,
info: MessageInfo,
chains_info: Vec<ChainInfoMsg>,
chains_info: ChainsInfo,
) -> Result<Response, ContractError> {
let config = CONFIG.load(deps.storage)?;
utils::authorize_execution(config, info.sender)?;

for chain_info in chains_info {
for chain_info in &chains_info.protocols_info {
let (chain_id, chain_info) = chain_info.to_chain_info(env.block.time);
CHAINS_INFO.save(deps.storage, chain_id, &chain_info)?;
}

let luna_info = chains_info.to_luna_info(env.block.time);
LUNA_INFO.save(deps.storage, &luna_info)?;

Ok(Response::new().add_attribute("action", "update_chains_info"))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::Config => to_binary(&CONFIG.load(deps.storage)?),
QueryMsg::ChainInfo { chain_id } => to_binary(&CHAINS_INFO.load(deps.storage, chain_id)?),
QueryMsg::ChainsInfo => {
let items = CHAINS_INFO
.range(deps.storage, None, None, Order::Ascending)
.collect::<StdResult<Vec<(ChainId, ChainInfo)>>>()?;
QueryMsg::LunaInfo => get_luna_info(deps,env),
QueryMsg::ChainInfo { chain_id } => get_chain_info(deps, env, chain_id),
QueryMsg::ChainsInfo => get_chains_info(deps, env),
}
}

pub fn get_luna_info(deps: Deps, env: Env) -> StdResult<Binary>{
let luna_info = &LUNA_INFO.load(deps.storage)?;
let cfg = CONFIG.load(deps.storage)?;

luna_info.is_expired(cfg.data_expiry_seconds, env.block.time)?;

to_binary(luna_info)
}

to_binary(&items)
pub fn get_chain_info(deps: Deps, env: Env, chain_id: ChainId) -> StdResult<Binary> {
match CHAINS_INFO.load(deps.storage, chain_id.clone()) {
Ok(chain_info) => {
let cfg = CONFIG.load(deps.storage)?;
chain_info.is_expired(cfg.data_expiry_seconds, env.block.time)?;

to_binary(&chain_info)
}
Err(_) => {
let string_error = format!("Chain is not available by id: {:?}", chain_id);

return Err(StdError::generic_err(string_error));
}
}
}

#[cfg(test)]
mod tests {
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};

use super::*;

#[test]
fn proper_initialization() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
controller_addr: "controller_addr".to_string(),
governance_addr: "governance_addr".to_string(),
};
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
}
pub fn get_chains_info(deps: Deps, env: Env) -> StdResult<Binary> {
let items = CHAINS_INFO
.range(deps.storage, None, None, Order::Ascending)
.map(|item| {
let (chain_id, chain_info) = item?;
let cfg = CONFIG.load(deps.storage)?;

chain_info.is_expired(cfg.data_expiry_seconds, env.block.time)?;

Ok((chain_id, chain_info))
})
.collect::<StdResult<Vec<(ChainId, ChainInfo)>>>()?;

to_binary(&items)
}
16 changes: 0 additions & 16 deletions contracts/alliance-oracle/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,4 @@ pub enum ContractError {

#[error("Unauthorized")]
Unauthorized {},

#[error("Custom Error val: {val:?}")]
CustomError { val: String },
// Add any other custom errors you like here.
// Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
#[error("Only a single asset is allowed")]
OnlySingleAssetAllowed {},

#[error("Asset not whitelisted")]
AssetNotWhitelisted {},

#[error("Insufficient balance")]
InsufficientBalance {},

#[error("Amount cannot be zero")]
AmountCannotBeZero {},
}
2 changes: 2 additions & 0 deletions contracts/alliance-oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ pub mod contract;
mod error;
pub mod state;
pub mod utils;
#[cfg(test)]
pub mod tests;
10 changes: 2 additions & 8 deletions contracts/alliance-oracle/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
use alliance_protocol::alliance_oracle_types::{ChainId, ChainInfo};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use alliance_protocol::alliance_oracle_types::{ChainId, ChainInfo, Config, LunaInfo};
use cw_storage_plus::{Item, Map};

#[cw_serde]
pub struct Config {
pub governance_addr: Addr,
pub controller_addr: Addr,
}

pub const CONFIG: Item<Config> = Item::new("config");
pub const CHAINS_INFO: Map<ChainId, ChainInfo> = Map::new("chains_info");
pub const LUNA_INFO: Item<LunaInfo> = Item::new("luna_info");
81 changes: 81 additions & 0 deletions contracts/alliance-oracle/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use alliance_protocol::alliance_oracle_types::{
ChainInfoMsg, ChainsInfo, ExecuteMsg, LunaAlliance, NativeToken, QueryMsg, ChainId, ChainInfo, LunaInfo
};
use cosmwasm_std::{
testing::{mock_env, mock_info},
Decimal, from_binary,
};
use std::str::FromStr;
use crate::{contract::{execute, query}};

pub mod test_utils;

#[test]
fn test_update_oracle_data() {
// Create the environment where the contract will be executed
let mut deps = test_utils::setup_contract();

// Msg representing off-chain oracle data that is send to the oracle contract
let msg = ExecuteMsg::UpdateChainsInfo {
chains_info: ChainsInfo {
luna_price: Decimal::from_str("0.589013565473308100").unwrap(),
protocols_info: vec![ChainInfoMsg {
chain_id: "chain-1".to_string(),
native_token: NativeToken {
denom: "udenom".to_string(),
token_price: Decimal::from_str("0.028076098081623823").unwrap(),
annual_inflation: Decimal::from_str("0.04").unwrap(),
},
luna_alliances: vec![LunaAlliance {
ibc_denom: String::from(
"ibc/05238E98A143496C8AF2B6067BABC84503909ECE9E45FBCBAC2CBA5C889FD82A",
),
normalized_reward_weight: Decimal::from_str("0.023809523809523810").unwrap(),
annual_take_rate: Decimal::from_str("0.009999998624824108").unwrap(),
total_lsd_staked: Decimal::from_str("126195.966393").unwrap(),
rebase_factor: Decimal::from_str("1.178655688356438636").unwrap(),
}],
}],
},
};

// Create the controller_addr sender to successfully send the transaction to the contract
let info = mock_info("controller_addr", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(1, res.attributes.len());
assert_eq!("action", res.attributes[0].key);
assert_eq!("update_chains_info", res.attributes[0].value);


// Query only the chains info to validate the data was stored correctly in the contract
let res = query(deps.as_ref(), mock_env(), QueryMsg::ChainsInfo).unwrap();
let res: Vec<(ChainId, ChainInfo)> = from_binary(&res).unwrap();
assert_eq!(1, res.len());

let key = res[0].0.clone();
assert_eq!("chain-1", key);

let chain_info = res[0].1.clone();
assert_eq!(NativeToken {
denom: "udenom".to_string(),
token_price: Decimal::from_str("0.028076098081623823").unwrap(),
annual_inflation: Decimal::from_str("0.04").unwrap(),
}, chain_info.native_token);

let luna_alliances = chain_info.luna_alliances.clone();
assert_eq!(1, luna_alliances.len());
assert_eq!(LunaAlliance {
ibc_denom: String::from(
"ibc/05238E98A143496C8AF2B6067BABC84503909ECE9E45FBCBAC2CBA5C889FD82A",
),
normalized_reward_weight: Decimal::from_str("0.023809523809523810").unwrap(),
annual_take_rate: Decimal::from_str("0.009999998624824108").unwrap(),
total_lsd_staked: Decimal::from_str("126195.966393").unwrap(),
rebase_factor: Decimal::from_str("1.178655688356438636").unwrap(),
}, luna_alliances[0]);

// Query the Luna info to validate the data was stored correctly in the contract
let res = query(deps.as_ref(), mock_env(), QueryMsg::LunaInfo).unwrap();
let luna_info: LunaInfo = from_binary(&res).unwrap();
assert_eq!(Decimal::from_str("0.589013565473308100").unwrap(), luna_info.luna_price);
}
26 changes: 26 additions & 0 deletions contracts/alliance-oracle/src/tests/test_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use alliance_protocol::alliance_oracle_types::{InstantiateMsg, QueryMsg, Config};
use cosmwasm_std::{testing::{mock_dependencies, mock_info, mock_env, MockStorage, MockApi, MockQuerier}, from_binary, OwnedDeps, Empty};

use crate::contract::{instantiate, query};


pub fn setup_contract() -> OwnedDeps<MockStorage, MockApi, MockQuerier, Empty> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
data_expiry_seconds: 60,
controller_addr: "controller_addr".to_string(),
governance_addr: "governance_addr".to_string(),
};
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(0, res.messages.len());

let cfg = query(deps.as_ref(), mock_env(), QueryMsg::Config).unwrap();

let cfg: Config = from_binary(&cfg).unwrap();
assert_eq!("controller_addr", cfg.controller_addr);
assert_eq!("governance_addr", cfg.governance_addr);
assert_eq!(60, cfg.data_expiry_seconds);

deps
}
5 changes: 3 additions & 2 deletions contracts/alliance-oracle/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use alliance_protocol::alliance_oracle_types::Config;
use cosmwasm_std::Addr;

use crate::{error::ContractError, state::Config};
use crate::{error::ContractError};

pub fn authorize_execution(config: Config, addr: Addr) -> Result<(), ContractError> {
if addr != config.controller_addr || addr != config.governance_addr {
if addr != config.controller_addr && addr != config.governance_addr {
return Err(ContractError::Unauthorized {});
}

Expand Down
Loading

0 comments on commit 22c0739

Please sign in to comment.