diff --git a/contracts/staking/src/contract.rs b/contracts/staking/src/contract.rs index 50fc78e0..8a3e11cd 100644 --- a/contracts/staking/src/contract.rs +++ b/contracts/staking/src/contract.rs @@ -5,8 +5,8 @@ use crate::execute::{ use crate::helpers::validate_addresses; use crate::ibc::{receive_ack, receive_timeout}; use crate::query::{ - query_batch, query_batches, query_claimable, query_config, query_ibc_queue, - query_pending_batch, query_reply_queue, query_state, + query_batch, query_batches, query_config, query_ibc_queue, query_pending_batch, + query_reply_queue, query_state, query_unstake_requests, }; use crate::state::{ new_unstake_request, Config, MultisigAddressConfig, ProtocolFeeConfig, State, ADMIN, BATCHES, @@ -30,6 +30,7 @@ use cw2::set_contract_version; use cw_utils::must_pay; use milky_way::staking::Batch; use osmosis_std::types::osmosis::tokenfactory::v1beta1::MsgCreateDenom; +use schemars::Map; use semver::Version; // Version information for migration @@ -265,11 +266,16 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { status, } => to_binary(&query_batches(deps, start_after, limit, status)?), QueryMsg::PendingBatch {} => to_binary(&query_pending_batch(deps)?), - QueryMsg::ClaimableBatches { + QueryMsg::UnstakeRequests { user, start_after, limit, - } => to_binary(&query_claimable(deps, user, start_after, limit)?), + } => to_binary(&query_unstake_requests( + deps, + user.to_string(), + start_after, + limit, + )?), // dev only, depr QueryMsg::IbcQueue { start_after, limit } => { @@ -318,6 +324,7 @@ pub fn migrate(mut deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result::new(); + let mut request_count = Map::::new(); let requests = BATCHES .range(deps.storage, None, None, cosmwasm_std::Order::Ascending) .map(|v| { @@ -326,6 +333,7 @@ pub fn migrate(mut deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result Result StdResult { let mut batch = b.unwrap(); batch.liquid_unstake_requests = None; + batch.unstake_requests_count = request_count.get(&batch_id).cloned(); Ok(batch) })?; } diff --git a/contracts/staking/src/execute.rs b/contracts/staking/src/execute.rs index d25fb3a6..8d7ee0a7 100644 --- a/contracts/staking/src/execute.rs +++ b/contracts/staking/src/execute.rs @@ -10,9 +10,7 @@ use crate::state::{ Config, IbcWaitingForReply, MultisigAddressConfig, ProtocolFeeConfig, State, ADMIN, BATCHES, CONFIG, IBC_WAITING_FOR_REPLY, INFLIGHT_PACKETS, PENDING_BATCH_ID, STATE, }; -use crate::state::{ - new_unstake_request, remove_unstake_request, UNSTAKE_REQUESTS, UNSTAKE_REQUEST_COUNTERS, -}; +use crate::state::{new_unstake_request, remove_unstake_request, unstake_requests, UnstakeRequest}; use cosmwasm_std::{ ensure, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, IbcTimeout, MessageInfo, Order, ReplyOn, Response, SubMsg, SubMsgResponse, SubMsgResult, Timestamp, Uint128, @@ -243,16 +241,26 @@ pub fn execute_liquid_unstake( // Add unstake request to pending batch let pending_unstake_request = - UNSTAKE_REQUESTS.load(deps.storage, (pending_batch_id, info.sender.to_string())); + unstake_requests().may_load(deps.storage, (pending_batch_id, info.sender.to_string()))?; + let is_new_request = pending_unstake_request.is_none(); match pending_unstake_request { - Ok(current_amount) => { - UNSTAKE_REQUESTS.save( + Some(_) => { + unstake_requests().update( deps.storage, (pending_batch_id, info.sender.to_string()), - &(current_amount + amount), + |or| -> Result { + match or { + Some(r) => Ok(UnstakeRequest { + batch_id: r.batch_id, + user: r.user.clone(), + amount: r.amount + amount, + }), + None => Err(ContractError::NoRequestInBatch {}), + } + }, )?; } - Err(_) => { + None => { new_unstake_request(&mut deps, info.sender.to_string(), pending_batch_id, amount)?; } } @@ -264,28 +272,13 @@ pub fn execute_liquid_unstake( |_batch| -> Result { let mut batch = _batch.unwrap(); batch.batch_total_liquid_stake += amount; + if is_new_request { + batch.unstake_requests_count = Some(batch.unstake_requests_count.unwrap_or(0) + 1); + } Ok(batch) }, )?; - // let mut msgs: Vec = vec![]; - // if batch period has elapsed, submit batch - // for simplicity not doing this for now - // if let Some(est_next_batch_action) = pending_batch.next_batch_action_time { - // if est_next_batch_action >= env.block.time.seconds() { - // msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { - // contract_addr: env.contract.address.to_string(), - // msg: to_binary(&ExecuteMsg::SubmitBatch { - // batch_id: pending_batch_id, - // })?, - // funds: vec![], - // })) - // } - - // // Save updated pending batch - // PENDING_BATCH.save(deps.storage, &pending_batch)?; - // } - Ok(Response::new() .add_attribute("action", "liquid_unstake") .add_attribute("sender", info.sender.to_string()) @@ -323,7 +316,12 @@ pub fn execute_submit_batch( expected: 0u64, }); } - let unstake_requests = UNSTAKE_REQUEST_COUNTERS.load(deps.storage, batch.id)?; + + let unstake_requests = unstake_requests() + .prefix(pending_batch_id) + .range(deps.storage, None, None, Order::Ascending) + .take(1) + .count(); if unstake_requests == 0 { return Err(ContractError::BatchEmpty {}); @@ -428,16 +426,15 @@ pub fn execute_withdraw( let received_native_unstaked = batch.received_native_unstaked.as_ref().unwrap(); let _liquid_unstake_request = - UNSTAKE_REQUESTS.load(deps.storage, (batch.id, info.sender.to_string())); - - if _liquid_unstake_request.is_err() { + unstake_requests().may_load(deps.storage, (batch.id, info.sender.to_string()))?; + if _liquid_unstake_request.is_none() { return Err(ContractError::NoRequestInBatch {}); } - let liquid_unstake_request = _liquid_unstake_request.unwrap(); + let unstake_request_amount = _liquid_unstake_request.unwrap().amount; let amount = received_native_unstaked - .multiply_ratio(liquid_unstake_request, batch.batch_total_liquid_stake); + .multiply_ratio(unstake_request_amount, batch.batch_total_liquid_stake); // TODO: if all liquid unstake requests have been withdrawn, delete the batch? remove_unstake_request(&mut deps, info.sender.to_string(), batch.id)?; diff --git a/contracts/staking/src/msg.rs b/contracts/staking/src/msg.rs index 1ad94618..b8863332 100644 --- a/contracts/staking/src/msg.rs +++ b/contracts/staking/src/msg.rs @@ -126,9 +126,9 @@ pub struct BatchResponse { pub batch_total_liquid_stake: Uint128, pub expected_native_unstaked: Uint128, pub received_native_unstaked: Uint128, + pub unstake_request_count: u64, pub next_batch_action_time: Timestamp, pub status: String, - pub requests: Vec, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] pub struct BatchesResponse { @@ -161,7 +161,7 @@ pub enum QueryMsg { #[returns(BatchResponse)] PendingBatch {}, #[returns(BatchesResponse)] - ClaimableBatches { + UnstakeRequests { user: Addr, start_after: Option, limit: Option, diff --git a/contracts/staking/src/query.rs b/contracts/staking/src/query.rs index 914f35d2..e7052d9c 100644 --- a/contracts/staking/src/query.rs +++ b/contracts/staking/src/query.rs @@ -1,14 +1,14 @@ use crate::helpers::{get_redemption_rate, paginate_map}; use crate::msg::{ BatchResponse, BatchesResponse, ConfigResponse, IBCQueueResponse, IBCReplyQueueResponse, - LiquidUnstakeRequestResponse, StateResponse, + StateResponse, }; use crate::state::ibc::IBCTransfer; use crate::state::{ - BATCHES, CONFIG, IBC_WAITING_FOR_REPLY, INFLIGHT_PACKETS, PENDING_BATCH_ID, STATE, - UNSTAKE_REQUESTS, UNSTAKE_REQUESTS_BY_USER, + unstake_requests, BATCHES, CONFIG, IBC_WAITING_FOR_REPLY, INFLIGHT_PACKETS, PENDING_BATCH_ID, + STATE, }; -use cosmwasm_std::{Addr, Deps, StdResult, Timestamp, Uint128}; +use cosmwasm_std::{Deps, StdResult, Timestamp, Uint128}; use cw_storage_plus::Bound; use milky_way::staking::{Batch, BatchStatus}; @@ -66,12 +66,7 @@ pub fn query_state(deps: Deps) -> StdResult { Ok(res) } -fn batch_to_response(deps: Deps, batch: Batch) -> BatchResponse { - let unstake_requests = UNSTAKE_REQUESTS - .prefix(batch.id) - .range(deps.storage, None, None, cosmwasm_std::Order::Ascending) - .map(|v| v.unwrap()) - .collect::>(); +fn batch_to_response(batch: Batch) -> BatchResponse { BatchResponse { id: batch.id, batch_total_liquid_stake: batch.batch_total_liquid_stake, @@ -81,19 +76,13 @@ fn batch_to_response(deps: Deps, batch: Batch) -> BatchResponse { batch.next_batch_action_time.unwrap_or(0u64), ), status: batch.status.as_str().to_string(), - requests: unstake_requests - .into_iter() - .map(|v| LiquidUnstakeRequestResponse { - user: v.0, - amount: v.1, - }) - .collect(), + unstake_request_count: batch.unstake_requests_count.unwrap_or(0), // Fallback. Only is none if migration failed. Would be set in updates for new batches though } } pub fn query_batch(deps: Deps, id: u64) -> StdResult { let batch: Batch = BATCHES.load(deps.storage, id)?; - Ok(batch_to_response(deps, batch)) + Ok(batch_to_response(batch)) } pub fn query_batches( @@ -115,10 +104,7 @@ pub fn query_batches( )?; let res = BatchesResponse { - batches: batches - .into_iter() - .map(|v| batch_to_response(deps, v)) - .collect(), + batches: batches.into_iter().map(|v| batch_to_response(v)).collect(), }; Ok(res) } @@ -127,7 +113,7 @@ pub fn query_pending_batch(deps: Deps) -> StdResult { let pending_batch_id = PENDING_BATCH_ID.load(deps.storage)?; let pending_batch = BATCHES.load(deps.storage, pending_batch_id)?; - Ok(batch_to_response(deps, pending_batch)) + Ok(batch_to_response(pending_batch)) } pub fn query_ibc_queue( @@ -169,15 +155,15 @@ pub fn query_reply_queue( Ok(res) } -pub fn query_claimable( +pub fn query_unstake_requests( deps: Deps, - user: Addr, + user: String, start_after: Option, limit: Option, ) -> StdResult { - deps.api.addr_validate(&user.to_string())?; - - let unstaking_requests = UNSTAKE_REQUESTS_BY_USER + let unstaking_requests = unstake_requests() + .idx + .by_user .prefix(user.to_string()) .range( deps.storage, @@ -192,15 +178,11 @@ pub fn query_claimable( let batches = unstaking_requests .into_iter() .filter_map(|v| { - let batch_id = v.0; + let batch_id = v.1.batch_id; let batch = BATCHES.load(deps.storage, batch_id).ok()?; - if batch.status == BatchStatus::Received { - Some(batch) - } else { - None - } + Some(batch) }) - .map(|v| batch_to_response(deps, v)) + .map(|v| batch_to_response(v)) .collect(); let res = BatchesResponse { batches }; diff --git a/contracts/staking/src/state.rs b/contracts/staking/src/state.rs index ed2724e2..ebce8dd9 100644 --- a/contracts/staking/src/state.rs +++ b/contracts/staking/src/state.rs @@ -1,7 +1,7 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, DepsMut, StdError, Timestamp, Uint128}; use cw_controllers::Admin; -use cw_storage_plus::{Item, Map}; +use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, UniqueIndex}; use milky_way::staking::Batch; #[cw_serde] @@ -51,24 +51,51 @@ pub const CONFIG: Item = Item::new("config"); pub const ADMIN: Admin = Admin::new("admin"); pub const STATE: Item = Item::new("state"); pub const BATCHES: Map = Map::new("batches"); -// -pub const UNSTAKE_REQUESTS: Map<(u64, String), Uint128> = Map::new("unstake_requests"); -pub const UNSTAKE_REQUESTS_BY_USER: Map<(String, u64), bool> = Map::new("unstake_requests_by_user"); -pub const UNSTAKE_REQUEST_COUNTERS: Map = Map::new("unstake_request_counters"); pub const PENDING_BATCH_ID: Item = Item::new("pending_batch_id"); +#[cw_serde] +pub struct UnstakeRequest { + pub batch_id: u64, + pub user: String, + pub amount: Uint128, +} + +pub struct UnstakeRequestIndexes<'a> { + pub by_user: UniqueIndex<'a, (String, u64), UnstakeRequest>, +} + +impl<'a> IndexList for UnstakeRequestIndexes<'a> { + fn get_indexes(&'_ self) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.by_user]; + Box::new(v.into_iter()) + } +} + +pub fn unstake_requests<'a>( +) -> IndexedMap<'a, (u64, String), UnstakeRequest, UnstakeRequestIndexes<'a>> { + let indexes = UnstakeRequestIndexes { + by_user: UniqueIndex::new(|r| (r.user.clone(), r.batch_id), "unstake_requests_by_user"), + }; + + // depr version + IndexedMap::new("unstake_requests", indexes) +} + pub fn new_unstake_request( deps: &mut DepsMut, user: String, batch_id: u64, amount: Uint128, ) -> Result<(), StdError> { - UNSTAKE_REQUESTS.save(deps.storage, (batch_id, user.clone()), &amount)?; - UNSTAKE_REQUEST_COUNTERS.update(deps.storage, batch_id, |c| match c { - Some(c) => Ok::(c + 1), - None => Ok(1), - })?; - UNSTAKE_REQUESTS_BY_USER.save(deps.storage, (user, batch_id), &true)?; + unstake_requests().save( + deps.storage, + (batch_id, user.clone()), + &UnstakeRequest { + batch_id, + user, + amount, + }, + )?; Ok(()) } @@ -77,12 +104,9 @@ pub fn remove_unstake_request( user: String, batch_id: u64, ) -> Result<(), StdError> { - UNSTAKE_REQUESTS.remove(deps.storage, (batch_id, user.clone())); - UNSTAKE_REQUEST_COUNTERS.update(deps.storage, batch_id, |c| match c { - Some(c) => Ok::(c - 1), - None => Ok(0), - })?; - UNSTAKE_REQUESTS_BY_USER.remove(deps.storage, (user, batch_id)); + unstake_requests() + .remove(deps.storage, (batch_id, user.clone())) + .unwrap(); Ok(()) } diff --git a/contracts/staking/src/tests/query_tests.rs b/contracts/staking/src/tests/query_tests.rs index 9179e807..80dd1d41 100644 --- a/contracts/staking/src/tests/query_tests.rs +++ b/contracts/staking/src/tests/query_tests.rs @@ -3,8 +3,7 @@ mod query_tests { // use serde_json; use crate::contract::{execute, query}; use crate::msg::{ - BatchResponse, BatchesResponse, ConfigResponse, ExecuteMsg, LiquidUnstakeRequestResponse, - QueryMsg, StateResponse, + BatchResponse, BatchesResponse, ConfigResponse, ExecuteMsg, QueryMsg, StateResponse, }; use crate::query::query_pending_batch; use crate::state::{CONFIG, STATE}; @@ -112,7 +111,6 @@ mod query_tests { assert_eq!(res.batch_total_liquid_stake, Uint128::from(0u128)); assert_eq!(res.expected_native_unstaked, Uint128::from(0u128)); assert_eq!(res.status, "pending".to_string()); - assert_eq!(res.requests.len(), 0); } Err(e) => match e { _ => panic!("Unexpected error: {:?}", e), @@ -142,20 +140,6 @@ mod query_tests { assert_eq!(res.batch_total_liquid_stake, Uint128::from(2000u128)); assert_eq!(res.expected_native_unstaked, Uint128::from(0u128)); assert_eq!(res.status, "pending".to_string()); - assert_eq!(res.requests.len(), 2); - assert_eq!( - res.requests, - vec![ - LiquidUnstakeRequestResponse { - user: "alice".to_string(), - amount: Uint128::from(1500u128), - }, - LiquidUnstakeRequestResponse { - user: "bob".to_string(), - amount: Uint128::from(500u128), - }, - ] - ) } Err(e) => match e { _ => panic!("Unexpected error: {:?}", e), @@ -232,14 +216,6 @@ mod query_tests { Uint128::from(1500u128) ); assert_eq!(first_batch.status, "submitted".to_string()); - assert_eq!(first_batch.requests.len(), 1); - assert_eq!( - first_batch.requests, - vec![LiquidUnstakeRequestResponse { - user: "bob".to_string(), - amount: Uint128::from(500u128), - }] - ) } else { panic!("batches is empty"); } @@ -251,14 +227,6 @@ mod query_tests { ); assert_eq!(first_batch.expected_native_unstaked, Uint128::from(0u128)); assert_eq!(first_batch.status, "pending".to_string()); - assert_eq!(first_batch.requests.len(), 1); - assert_eq!( - first_batch.requests, - vec![LiquidUnstakeRequestResponse { - user: "alice".to_string(), - amount: Uint128::from(1500u128), - }] - ) } else { panic!("batches is empty"); } diff --git a/contracts/staking/src/tests/unstake_tests.rs b/contracts/staking/src/tests/unstake_tests.rs index c21b85e0..a4d10954 100644 --- a/contracts/staking/src/tests/unstake_tests.rs +++ b/contracts/staking/src/tests/unstake_tests.rs @@ -7,7 +7,7 @@ mod staking_tests { use crate::msg::ExecuteMsg; use crate::msg::QueryMsg; use crate::state::new_unstake_request; - use crate::state::UNSTAKE_REQUESTS; + use crate::state::unstake_requests; use crate::state::{Config, BATCHES, CONFIG, STATE}; use crate::tests::test_helper::init; use cosmwasm_std::from_binary; @@ -80,13 +80,16 @@ mod staking_tests { assert!(res.is_ok()); // Check pending batch - let unstake_requests = UNSTAKE_REQUESTS + let unstake_requests_records = unstake_requests() .prefix(1u64) .range(&deps.storage, None, None, cosmwasm_std::Order::Ascending) .map(|v| v.unwrap()) .collect::>(); - assert!(unstake_requests.len() == 1); - assert_eq!(unstake_requests.get(0).unwrap().1, Uint128::from(1500u128)); + assert!(unstake_requests_records.len() == 1); + assert_eq!( + unstake_requests_records.get(0).unwrap().1.amount, + Uint128::from(1500u128) + ); // Alice unstakes 5_000 let info = mock_info("alice", &coins(5_000, "factory/cosmos2contract/stTIA")); @@ -99,19 +102,29 @@ mod staking_tests { pending_batch.batch_total_liquid_stake, Uint128::from(6_500u128) ); - let unstake_requests = UNSTAKE_REQUESTS + let unstake_requests_records = unstake_requests() .prefix(1u64) .range(&deps.storage, None, None, cosmwasm_std::Order::Ascending) .map(|v| v.unwrap()) .collect::>(); - assert!(unstake_requests.len() == 2); //for bob & alice + assert!(unstake_requests_records.len() == 2); //for bob & alice assert_eq!( - unstake_requests.iter().find(|v| v.0 == "bob").unwrap().1, + unstake_requests_records + .iter() + .find(|v| v.0 == "bob") + .unwrap() + .1 + .amount, Uint128::from(1500u128) ); assert_eq!( - unstake_requests.iter().find(|v| v.0 == "alice").unwrap().1, + unstake_requests_records + .iter() + .find(|v| v.0 == "alice") + .unwrap() + .1 + .amount, Uint128::from(5000u128) ); @@ -372,20 +385,27 @@ mod staking_tests { let res = BATCHES.save(&mut deps.storage, 2, &batch_2); assert!(res.is_ok()); - let claimable_batches_res = query( + let unstake_requests_res = query( deps.as_ref(), mock_env(), - QueryMsg::ClaimableBatches { + QueryMsg::UnstakeRequests { user: Addr::unchecked("bob"), start_after: None, limit: None, }, ); - assert!(claimable_batches_res.is_ok()); - let claimable_batches_res = from_binary::(&claimable_batches_res.unwrap()); - assert!(claimable_batches_res.is_ok()); - let claimable_batches = claimable_batches_res.unwrap(); - assert_eq!(claimable_batches.batches.len(), 0); + assert!(unstake_requests_res.is_ok()); + let unstake_requests_res = from_binary::(&unstake_requests_res.unwrap()); + assert!(unstake_requests_res.is_ok()); + let unstake_requests = unstake_requests_res.unwrap(); + assert_eq!( + unstake_requests + .batches + .iter() + .filter(|v| v.status == "received") + .count(), + 0 + ); // receive tokens for batch 1 let mut batch: Batch = BATCHES.load(&deps.storage, 1).unwrap(); @@ -414,20 +434,27 @@ mod staking_tests { let res = execute(deps.as_mut(), mock_env(), info, msg); assert!(res.is_ok()); - let claimable_batches_res = query( + let unstake_requests_res = query( deps.as_ref(), mock_env(), - QueryMsg::ClaimableBatches { + QueryMsg::UnstakeRequests { user: Addr::unchecked("bob"), start_after: None, limit: None, }, ); - assert!(claimable_batches_res.is_ok()); - let claimable_batches_res = from_binary::(&claimable_batches_res.unwrap()); - assert!(claimable_batches_res.is_ok()); - let claimable_batches = claimable_batches_res.unwrap(); - assert_eq!(claimable_batches.batches.len(), 1); - assert_eq!(claimable_batches.batches[0].id, 1); + assert!(unstake_requests_res.is_ok()); + let unstake_requests_res = from_binary::(&unstake_requests_res.unwrap()); + assert!(unstake_requests_res.is_ok()); + let unstake_requests = unstake_requests_res.unwrap(); + assert_eq!( + unstake_requests + .batches + .iter() + .filter(|v| v.status == "received") + .count(), + 1 + ); + assert_eq!(unstake_requests.batches.get(0).unwrap().id, 1); } } diff --git a/contracts/staking/src/tests/withdraw_tests.rs b/contracts/staking/src/tests/withdraw_tests.rs index 9dd862f7..19a9e70e 100644 --- a/contracts/staking/src/tests/withdraw_tests.rs +++ b/contracts/staking/src/tests/withdraw_tests.rs @@ -72,7 +72,7 @@ mod withdraw_tests { let messages = res.unwrap().messages; assert_eq!(messages.len(), 2); // withdraw and redemption rate update - let msg = QueryMsg::ClaimableBatches { + let msg = QueryMsg::UnstakeRequests { user: Addr::unchecked("bob"), start_after: None, limit: None, @@ -116,7 +116,7 @@ mod withdraw_tests { let messages = res.unwrap().messages; assert_eq!(messages.len(), 2); // withdraw and redemption rate update - let msg = QueryMsg::ClaimableBatches { + let msg = QueryMsg::UnstakeRequests { user: Addr::unchecked("tom"), start_after: None, limit: None, @@ -196,7 +196,7 @@ mod withdraw_tests { let messages = res.unwrap().messages; assert_eq!(messages.len(), 2); // withdraw and redemption rate update - let msg = QueryMsg::ClaimableBatches { + let msg = QueryMsg::UnstakeRequests { user: Addr::unchecked("bob"), start_after: None, limit: None, @@ -240,7 +240,7 @@ mod withdraw_tests { let messages = res.unwrap().messages; assert_eq!(messages.len(), 2); // withdraw and redemption rate update - let msg = QueryMsg::ClaimableBatches { + let msg = QueryMsg::UnstakeRequests { user: Addr::unchecked("tom"), start_after: None, limit: None, diff --git a/packages/milky_way/src/staking.rs b/packages/milky_way/src/staking.rs index d07b80c6..fd27bd42 100644 --- a/packages/milky_way/src/staking.rs +++ b/packages/milky_way/src/staking.rs @@ -31,6 +31,8 @@ pub struct Batch { pub received_native_unstaked: Option, pub liquid_unstake_requests: Option>, + pub unstake_requests_count: Option, + /// Estimated time when next batch action occurs pub next_batch_action_time: Option, @@ -44,12 +46,12 @@ impl Batch { Self { id, batch_total_liquid_stake: batch_total, - // liquid_unstake_requests: Map::new(), next_batch_action_time: Some(est_next_batch_action), status: BatchStatus::Pending, expected_native_unstaked: None, received_native_unstaked: None, liquid_unstake_requests: None, + unstake_requests_count: Some(0), } } pub fn update_status(&mut self, new_status: BatchStatus, next_action: Option) { diff --git a/scripts/tests/test_200_batch.sh b/scripts/tests/test_200_batch.sh index 55a515dd..fa1f15e6 100644 --- a/scripts/tests/test_200_batch.sh +++ b/scripts/tests/test_200_batch.sh @@ -12,7 +12,7 @@ function awaitTx() { done } -# create 200 wallets in osmosis +# create 200 wallets in osmosis (just need to do once locally) for i in {1..200} do echo "Creating wallet $i" @@ -32,11 +32,6 @@ osmosisd tx bank multi-send $ADMIN_OSMOSIS "${ALL_ADDRESSES[@]}" 200000stake \ --chain-id osmosis-dev-1 --broadcast-mode sync # ibc send 100000 utia to each wallet from celestia -# TXHASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 --from test_master --keyring-backend test \ -# --node http://localhost:26661 --chain-id celestia-dev-1 --fees 21000utia --output json -y \ -# $ADMIN_OSMOSIS 20000000utia --broadcast-mode sync --output json | jq -r '.txhash') -# awaitTx - # need to do in docker currently celestia-appd tx ibc-transfer transfer transfer channel-0 --from validator1 --keyring-backend test --home=$HOME/.celestia-app/validator1 \ --node http://localhost:26661 --chain-id celestia-dev-1 --fees 21000utia --output json -y \ @@ -60,7 +55,7 @@ awaitTx # STAKE_CONTRACT=osmo14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sq2r9g9 # liquid stake 100000 utia from each wallet -for i in {158..200} +for i in {1..200} do echo "Liquid staking wallet $i" # check if wallet has stake already @@ -75,11 +70,11 @@ do -y --gas-prices 0.025stake --gas-adjustment 1.7 --gas auto \ --broadcast-mode sync --chain-id osmosis-dev-1 \ --generate-only > unsignedTx.json - echo XXX osmosisd tx sign unsignedTx.json \ --from wallet$i --keyring-backend test --home ./osmosisd_test \ --chain-id osmosis-dev-1 --output-document signedTx.json - TXHASH=$(osmosisd tx broadcast signedTx.json --output json | jq -r '.txhash') + RES=$(osmosisd tx broadcast signedTx.json --output json) + TXHASH=$(echo $RES | jq -r '.txhash') echo $TXHASH # pause every 25 if [ $(( $i % 25 )) -eq 0 ]; then @@ -119,8 +114,13 @@ do osmosisd tx sign unsignedTx.json \ --from wallet$i --keyring-backend test --home ./osmosisd_test \ --chain-id osmosis-dev-1 --account-number $ACCOUNT_NUMBER --sequence $SEQUENCE --output-document signedTx.json - TXHASH=$(osmosisd tx broadcast signedTx.json --output json | jq -r '.txhash') + RES=$(osmosisd tx broadcast signedTx.json --output json) + TXHASH=$(echo $RES | jq -r '.txhash') + # awaitTx + # RES=$(osmosisd query tx $TXHASH --output json) + # GAS=$(echo $RES | jq -r '.gas_used') echo $TXHASH + # echo $GAS # pause every 25 if [ $(( $i % 25 )) -eq 0 ]; then echo "Pausing for 5 seconds" @@ -130,7 +130,8 @@ do done # count requests in batch -osmosisd query wasm contract-state smart $STAKE_CONTRACT '{"batches":{}}' --output json | jq -r '.data.batches[0].requests | length' +osmosisd query wasm contract-state smart $STAKE_CONTRACT '{"batches":{}}' --output json | jq -r '.data.batches[0].unstake_request_count' +osmosisd query wasm contract-state smart $STAKE_CONTRACT '{"unstake_requests":{"user":"osmo1z0um7jczylh6n7mh5s26grtydf02d8254kmaf6"}}' # check queue osmosisd query wasm contract-state smart $STAKE_CONTRACT '{"ibc_queue":{}}' --output json | jq -r '.data.ibc_queue' @@ -140,4 +141,15 @@ osmosisd tx wasm execute $STAKE_CONTRACT '{"submit_batch":{}}' \ --from test_master --keyring-backend test \ -y -b sync \ --gas-prices 0.025stake --gas-adjustment 1.7 --gas auto \ + --chain-id osmosis-dev-1 + +# receive rewards +MEMO='{"wasm":{"contract":"'$STAKE_CONTRACT'","msg":{"receive_unstaked_tokens":{"batch_id":1}}}}' +PACKET_SEQUENCE=$(celestia-appd tx ibc-transfer transfer transfer channel-0 --from test_master --node http://localhost:26661 --chain-id celestia-dev-1 --fees 21000utia --output json -y $STAKE_CONTRACT 10utia --broadcast-mode block --memo "$MEMO" | jq -r '.raw_log | fromjson | .[0].events[] | select(.type == "send_packet") | .attributes[] | select(.key == "packet_sequence") | .value') + +# withdraw tokens +osmosisd tx wasm execute $STAKE_CONTRACT '{"withdraw":{"batch_id":1}}' \ + --from wallet1 --keyring-backend test --home ./osmosisd_test \ + -y -b sync \ + --gas-prices 0.025stake --gas-adjustment 1.7 --gas auto \ --chain-id osmosis-dev-1 \ No newline at end of file