Skip to content

Commit

Permalink
CL deprecation code.
Browse files Browse the repository at this point in the history
  • Loading branch information
arhamchordia committed Dec 17, 2024
1 parent be0daa5 commit ead143d
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 12 deletions.
9 changes: 3 additions & 6 deletions smart-contracts/osmosis/contracts/cl-vault/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ use crate::msg::{
ClQueryMsg, ExecuteMsg, ExtensionExecuteMsg, ExtensionQueryMsg, InstantiateMsg, MigrateMsg,
ModifyRangeMsg, QueryMsg,
};
use crate::query::{
query_assets_from_shares, query_dex_router, query_info, query_metadata, query_pool,
query_position, query_total_assets, query_total_vault_token_supply, query_user_assets,
query_user_balance, query_verify_tick_cache, RangeAdminResponse,
};
use crate::query::{query_active_users, query_assets_from_shares, query_dex_router, query_info, query_metadata, query_pool, query_position, query_total_assets, query_total_vault_token_supply, query_user_assets, query_user_balance, query_verify_tick_cache, RangeAdminResponse};
use crate::reply::Replies;
use crate::state::{VaultConfig, VAULT_CONFIG};
use crate::vault::{
Expand Down Expand Up @@ -84,7 +80,7 @@ pub fn execute(
VaultStandardExecuteMsg::VaultExtension(vault_msg) => {
match vault_msg {
ExtensionExecuteMsg::Admin(admin_msg) => {
execute_admin(deps, info, admin_msg)
execute_admin(deps, env, info, admin_msg)
}
ExtensionExecuteMsg::Merge(msg) => {
execute_merge_position(deps, env, info, msg)
Expand Down Expand Up @@ -171,6 +167,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<Binary, ContractErro
}
ClQueryMsg::VerifyTickCache => Ok(to_json_binary(&query_verify_tick_cache(deps)?)?),
},
ExtensionQueryMsg::ActiveUsers {next_token, limit} => Ok(to_json_binary(&query_active_users(deps, next_token, limit)?)?),
},
}
}
Expand Down
3 changes: 3 additions & 0 deletions smart-contracts/osmosis/contracts/cl-vault/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ pub enum ContractError {
#[error("Position claim after period is not expired yet.")]
ClaimAfterNotExpired {},

#[error("Invalid token for paginated query")]
InvalidToken {},

// Imported errors
#[error("{0}")]
PaymentError(#[from] PaymentError),
Expand Down
13 changes: 12 additions & 1 deletion smart-contracts/osmosis/contracts/cl-vault/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Decimal};
use cosmwasm_std::{Addr, Decimal, Uint256};
use osmosis_std::types::osmosis::poolmanager::v1beta1::SwapAmountInRoute;
use quasar_types::cw_vault_multi_standard::{VaultStandardExecuteMsg, VaultStandardQueryMsg};

Expand Down Expand Up @@ -56,6 +56,10 @@ pub enum AdminExtensionExecuteMsg {
},
/// Build tick exponent cache
BuildTickCache {},
/// Auto claim endpoint
AutoWithdraw {
users: Vec<(Addr, Uint256)>,
}
}

#[cw_serde]
Expand Down Expand Up @@ -102,6 +106,13 @@ pub enum ExtensionQueryMsg {
ConcentratedLiquidity(ClQueryMsg),
/// Query the DexRouter address
DexRouter {},
/// Query active users
ActiveUsers {
/// Optional token for pagination
next_token: Option<String>,
/// Limit for the search
limit: u64,
},
}

/// Extension query messages for user balance related queries
Expand Down
79 changes: 79 additions & 0 deletions smart-contracts/osmosis/contracts/cl-vault/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ pub struct DexRouterResponse {
pub dex_router: String,
}

#[cw_serde]
pub struct ActiveUsersResponse {
pub users: Vec<String>, // List of user addresses only
pub next_token: Option<String>, // Token for the next page
}

pub fn query_verify_tick_cache(deps: Deps) -> Result<VerifyTickCacheResponse, ContractError> {
verify_tick_exp_cache(deps.storage)
.err()
Expand Down Expand Up @@ -172,6 +178,48 @@ pub fn query_user_balance(
Ok(UserSharesBalanceResponse { balance })
}

pub fn query_active_users(
deps: Deps,
next_token: Option<String>,
limit: u64,
) -> Result<ActiveUsersResponse, ContractError> {
let mut users: Vec<String> = Vec::new();
let mut start_index = 0;

// If there's a next_token, parse it to find the starting index
if let Some(token) = next_token {
start_index = token.parse::<usize>().map_err(|_| ContractError::InvalidToken { /* provide necessary fields if any */ })?;
}

// Iterate over the SHARES map to collect user addresses
for result in SHARES.range(deps.storage, None, None, cosmwasm_std::Order::Ascending) {
let (addr, _balance) = result.map_err(|e| ContractError::Std(e))?; // Handle the Result properly
let user_addr = addr;

// Only add users starting from the start_index
if start_index > 0 {
start_index -= 1;
continue;
}

users.push(user_addr.to_string());

// Stop if we reach the limit
if users.len() as u64 >= limit {
break;
}
}

// Determine the next token for pagination
let next_token = if users.len() as u64 == limit {
Some((start_index + limit as usize).to_string())
} else {
None
};

Ok(ActiveUsersResponse { users, next_token })
}

/// Vault base assets is the vault assets EXCLUDING any rewards claimable by strategist or users
pub fn query_total_assets(deps: Deps, env: Env) -> Result<TotalAssetsResponse, ContractError> {
let position = get_position(deps.storage, &deps.querier)?;
Expand Down Expand Up @@ -222,3 +270,34 @@ pub fn query_total_vault_token_supply(
.into();
Ok(TotalVaultTokenSupplyResponse { total })
}

#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::{testing::mock_dependencies, Addr, Uint128};

#[test]
fn test_query_active_users() {
let mut deps = mock_dependencies();

// Setup mock data in the SHARES map
let user1 = Addr::unchecked("user1");
let user2 = Addr::unchecked("user2");
let user3 = Addr::unchecked("user3");

// Insert mock user balances into SHARES
SHARES.save(deps.as_mut().storage, user1, &Uint128::new(100)).unwrap();
SHARES.save(deps.as_mut().storage, user2, &Uint128::new(200)).unwrap();
SHARES.save(deps.as_mut().storage, user3, &Uint128::new(300)).unwrap();

// Test without next_token and limit of 2
let res = query_active_users(deps.as_ref(), None, 2).unwrap();
assert_eq!(res.users, vec!["user1", "user2"]);
assert_eq!(res.next_token, Some("2".to_string())); // Expecting next_token for pagination

// Test with next_token to get the next user
let res = query_active_users(deps.as_ref(), Some("2".to_string()), 2).unwrap();
assert_eq!(res.users, vec!["user3"]);
assert_eq!(res.next_token, None); // No more users, so next_token should be None
}
}
40 changes: 39 additions & 1 deletion smart-contracts/osmosis/contracts/cl-vault/src/vault/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use crate::error::assert_admin;
use crate::math::tick::build_tick_exp_cache;
use crate::state::{Metadata, VaultConfig, ADMIN_ADDRESS, METADATA, RANGE_ADMIN, VAULT_CONFIG};
use crate::{msg::AdminExtensionExecuteMsg, ContractError};
use cosmwasm_std::{Decimal, DepsMut, MessageInfo, Response, StdError};
use cosmwasm_std::{Addr, Decimal, DepsMut, Env, MessageInfo, Response, StdError, Uint256};
use cw_utils::nonpayable;
use crate::vault::withdraw::execute_withdraw;

pub(crate) fn execute_admin(
deps: DepsMut,
env: Env,
info: MessageInfo,
admin_msg: AdminExtensionExecuteMsg,
) -> Result<Response, ContractError> {
Expand All @@ -24,6 +26,7 @@ pub(crate) fn execute_admin(
execute_update_range_admin(deps, info, address)
}
AdminExtensionExecuteMsg::BuildTickCache {} => execute_build_tick_exp_cache(deps, info),
AdminExtensionExecuteMsg::AutoWithdraw { users } => execute_auto_claim(deps, &env, info, users),
}
}

Expand Down Expand Up @@ -136,6 +139,41 @@ pub fn execute_build_tick_exp_cache(
.add_attribute("action", "build_tick_exp_cache"))
}

pub fn execute_auto_claim(
mut deps: DepsMut,
env: &Env,
info: MessageInfo,
users: Vec<(Addr, Uint256)>,
) -> Result<Response, ContractError> {
assert_admin(deps.storage, &info.sender)?;
let mut res = Response::new();

// Iterate over each address and execute withdraw
for user_data in users {
deps.api.addr_validate(user_data.0.as_str())?;

let user_info = MessageInfo {
sender: user_data.0.clone(),
funds: vec![],
};
let withdraw_response =
execute_withdraw(deps.branch(), env, user_info, Some(user_data.0.to_string()), user_data.1)?;

let withdraw_messages = withdraw_response
.messages
.iter()
.map(|sm| sm.msg.clone());

res = res
.add_messages(withdraw_messages)
.add_attributes(withdraw_response.attributes);
}

Ok(Response::new()
.add_attribute("method", "execute")
.add_attribute("action", "auto_withdraw"))
}

#[cfg(test)]
mod tests {
use crate::math::tick::{build_tick_exp_cache, verify_tick_exp_cache};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::setup::{fixture_default, PERFORMANCE_FEE_DEFAULT};
use cosmwasm_std::{Addr, Coin, Decimal, Uint128, Uint256};
use crate::setup::{fixture_default, fixture_dex_router, ACCOUNTS_INIT_BALANCE, ACCOUNTS_NUM, DENOM_BASE, DENOM_QUOTE, MAX_SLIPPAGE_HIGH, PERFORMANCE_FEE_DEFAULT};

use cl_vault::{
msg::{
AdminExtensionExecuteMsg, ClQueryMsg, ExecuteMsg, ExtensionExecuteMsg, ExtensionQueryMsg,
QueryMsg,
},
query::VerifyTickCacheResponse,
query::{ActiveUsersResponse, VerifyTickCacheResponse},
};
use osmosis_test_tube::{Module, Wasm};
use osmosis_test_tube::{Account, Module, Wasm};
use crate::any_deposit::do_and_verify_any_deposit;

#[test]
fn admin_build_tick_cache_works() {
Expand Down Expand Up @@ -44,3 +46,84 @@ fn admin_build_tick_cache_works() {
.unwrap();
assert!(verify_resp.result.is_ok());
}

#[test]
fn admin_execute_auto_claim_works() {
let (app, contract_address, _, _cl_pool_id, _, admin, _) = fixture_dex_router(PERFORMANCE_FEE_DEFAULT);
let wasm = Wasm::new(&app);

for _i in 1..10 {
let accounts = app
.init_accounts(
&[
Coin::new(ACCOUNTS_INIT_BALANCE, DENOM_BASE),
Coin::new(ACCOUNTS_INIT_BALANCE, DENOM_QUOTE),
Coin::new(ACCOUNTS_INIT_BALANCE, "uosmo"),
],
2,
)
.unwrap();

let amount_base = Uint128::new(10000);
let amount_quote = Uint128::new(10000);
let mut deposit_coins = vec![];
if amount_base > Uint128::zero() {
deposit_coins.push(Coin::new(amount_base.u128(), DENOM_BASE));
}
if amount_quote > Uint128::zero() {
deposit_coins.push(Coin::new(amount_quote.u128(), DENOM_QUOTE));
}
let _ = wasm.execute(
contract_address.as_str(),
&ExecuteMsg::AnyDeposit {
amount: amount_base,
asset: DENOM_BASE.to_string(),
recipient: Some(accounts[0].address()),
max_slippage: Decimal::bps(MAX_SLIPPAGE_HIGH),
},
&deposit_coins,
&accounts[0],
).unwrap();
}

let query_resp: ActiveUsersResponse = wasm
.query(
contract_address.as_str(),
&QueryMsg::VaultExtension(ExtensionQueryMsg::ActiveUsers {
limit: 10, // Adjust limit as needed
next_token: None,
}),
)
.unwrap();

assert!(!query_resp.users.is_empty(), "Expected users to be present");

let users: Vec<(Addr, Uint256)> = query_resp
.users
.iter()
.map(|user| {
let addr = Addr::unchecked(user); // Convert String to Addr
(addr, Uint256::from(100u128)) // Use from method to create Uint256
})
.collect();

let auto_claim_resp = wasm
.execute(
contract_address.as_str(),
&ExecuteMsg::VaultExtension(ExtensionExecuteMsg::Admin(
AdminExtensionExecuteMsg::AutoWithdraw { users },
)),
&[],
&admin,
)
.unwrap();

let has_expected_event = auto_claim_resp.events.iter().any(|event| {
event.ty == "wasm"
&& event
.attributes
.iter()
.any(|attr| attr.key == "action" && attr.value == "auto_withdraw")
});
assert!(has_expected_event, "Expected event not found in auto_claim_resp");
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn test_any_deposit() {
}
}

fn do_and_verify_any_deposit(
pub fn do_and_verify_any_deposit(
app: OsmosisTestApp,
contract_address: Addr,
vault_pool_id: u64,
Expand Down

0 comments on commit ead143d

Please sign in to comment.