From f43502b599886e564a6f33d9b6dfb619bad2a8cf Mon Sep 17 00:00:00 2001 From: nahem Date: Thu, 7 Mar 2024 18:35:37 +0100 Subject: [PATCH] fix(smart-contracts): fix bug to let users exit pool after auction is over --- contracts/injective-auction-pool/src/error.rs | 2 +- .../injective-auction-pool/src/executions.rs | 8 +- .../src/tests/test_helpers.rs | 98 ++++++++++++++++++- 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/contracts/injective-auction-pool/src/error.rs b/contracts/injective-auction-pool/src/error.rs index 416b8ec..4513d15 100644 --- a/contracts/injective-auction-pool/src/error.rs +++ b/contracts/injective-auction-pool/src/error.rs @@ -2,7 +2,7 @@ use cosmwasm_std::{Decimal, Instantiate2AddressError, OverflowError, StdError}; use cw_utils::PaymentError; use thiserror::Error; -#[derive(Error, Debug)] +#[derive(Error, Debug, PartialEq)] pub enum ContractError { #[error("{0}")] Std(#[from] StdError), diff --git a/contracts/injective-auction-pool/src/executions.rs b/contracts/injective-auction-pool/src/executions.rs index 82f1204..62f4f33 100644 --- a/contracts/injective-auction-pool/src/executions.rs +++ b/contracts/injective-auction-pool/src/executions.rs @@ -96,12 +96,14 @@ pub(crate) fn exit_pool( // prevents the user from exiting the pool in the last day of the auction if current_auction_round_response - .auction_closing_time - .ok_or(ContractError::CurrentAuctionQueryError)? + .auction_closing_time() .saturating_sub(env.block.time.seconds()) < DAY_IN_SECONDS + && env.block.time.seconds() < current_auction_round_response.auction_closing_time() { - return Err(ContractError::PooledAuctionLocked); + { + return Err(ContractError::PooledAuctionLocked); + } } // subtract the amount of INJ to send from the bidding balance diff --git a/contracts/injective-auction-pool/src/tests/test_helpers.rs b/contracts/injective-auction-pool/src/tests/test_helpers.rs index 877e482..c4f544a 100644 --- a/contracts/injective-auction-pool/src/tests/test_helpers.rs +++ b/contracts/injective-auction-pool/src/tests/test_helpers.rs @@ -1,6 +1,8 @@ use std::marker::PhantomData; -use cosmwasm_std::testing::{mock_env, mock_info, BankQuerier, MockApi, MockStorage}; +use cosmwasm_std::testing::{ + mock_env, mock_info, BankQuerier, MockApi, MockStorage, MOCK_CONTRACT_ADDR, +}; use cosmwasm_std::{ attr, coins, from_json, to_json_binary, BankMsg, Binary, ContractResult as CwContractResult, CosmosMsg, Decimal, Empty, Env, MemoryStorage, MessageInfo, OwnedDeps, Querier, QuerierResult, @@ -12,6 +14,7 @@ use treasurechest::tf::tokenfactory::TokenFactoryType; use crate::contract::{execute, instantiate}; use crate::state::BIDDING_BALANCE; +use crate::ContractError; pub struct AuctionQuerier { bank: BankQuerier, @@ -41,7 +44,8 @@ impl Querier for AuctionQuerier { amount: "10000".to_string(), }], auction_round: Some(1), - auction_closing_time: Some(10_000_000), + // simulates now + 7 days in seconds + auction_closing_time: Some(1_571_797_419 + 7 * 86_400), highest_bidder: Some("highest_bidder".to_string()), highest_bid_amount: Some("20000".to_string()), }) @@ -147,6 +151,7 @@ pub fn user_joins_pool() { }) ); + // checking attributes are fine assert_eq!( res.attributes, vec![ @@ -157,6 +162,93 @@ pub fn user_joins_pool() { ] ); - // contract balance should be 100 + // bidding balance should now be 100 assert_eq!(BIDDING_BALANCE.load(&deps.storage).unwrap(), Uint128::from(100u128)); } + +#[test] +fn user_exit_pool_works() { + let (mut deps, env) = init(); + + let info = mock_info("robinho", &coins(100, "native_denom")); + let msg = ExecuteMsg::JoinPool { + auction_round: 1, + basket_value: Uint128::from(10_000u128), + }; + let _ = execute(deps.as_mut().branch(), env.clone(), info, msg).unwrap(); + + let info = mock_info("robinho", &coins(100, format!("factory/{}/1", env.contract.address))); + let msg = ExecuteMsg::ExitPool {}; + + let res = execute(deps.as_mut().branch(), env.clone(), info, msg).unwrap(); + + // contract burns 100 lp tokens from the user + assert_eq!( + res.messages[0].msg, + TokenFactoryType::Injective.burn( + env.contract.address.clone(), + format!("factory/{}/1", env.contract.address).as_str(), + Uint128::from(100u128), + ) + ); + + // contract returns 100 native_denom to the user + assert_eq!( + res.messages[1].msg, + BankMsg::Send { + to_address: "robinho".to_string(), + amount: coins(100, "native_denom"), + } + .into() + ); + + // checking attributes are fine + assert_eq!(res.attributes, vec![attr("action", "exit_pool")]); +} + +#[test] +fn user_exit_pool_fails() { + let (mut deps, mut env) = init(); + + let info = mock_info("robinho", &coins(100, "native_denom")); + let msg = ExecuteMsg::JoinPool { + auction_round: 1, + basket_value: Uint128::from(10_000u128), + }; + let _ = execute(deps.as_mut().branch(), env.clone(), info, msg).unwrap(); + + let info = mock_info("robinho", &coins(100, format!("factory/{}/1", env.contract.address))); + let msg = ExecuteMsg::ExitPool {}; + + // move time to 6 days later (1+ day before auction ends) + env.block.time = env.block.time.plus_seconds(6 * 86_400 + 1); + + let res = execute(deps.as_mut().branch(), env.clone(), info.clone(), msg.clone()).unwrap_err(); + + // contract burns 100 lp tokens from the user + assert_eq!(res, ContractError::PooledAuctionLocked {}); + + // move time one more day, should be able to exit now + env.block.time = env.block.time.plus_seconds(86_400); + + let res = execute(deps.as_mut().branch(), env.clone(), info, msg).unwrap(); + assert_eq!( + res.messages[0].msg, + TokenFactoryType::Injective.burn( + env.contract.address.clone(), + format!("factory/{}/1", env.contract.address).as_str(), + Uint128::from(100u128), + ) + ); + + assert_eq!( + res.messages[1].msg, + BankMsg::Send { + to_address: "robinho".to_string(), + amount: coins(100, "native_denom"), + } + .into() + ); + + assert_eq!(res.attributes, vec![attr("action", "exit_pool")]); +}