Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optional withdrawer #75

Merged
merged 3 commits into from
Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/covenant/src/suite_test/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl Default for SuiteBuilder {
expected_native_token_amount: Uint128::new(1),
},
preset_holder_fields: covenant_holder::msg::PresetHolderFields {
withdrawer: CREATOR_ADDR.to_string(),
withdrawer: Some(CREATOR_ADDR.to_string()),
holder_code: 1,
label: "covenant_holder_contract".to_string(),
},
Expand Down
33 changes: 24 additions & 9 deletions contracts/holder/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,19 @@ pub fn instantiate(
) -> Result<Response, ContractError> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
deps.api.debug("WASMDEBUG: holder instantiate");
let mut resp = Response::default()
.add_attribute("method", "instantiate");

let withdrawer = deps.api.addr_validate(&msg.withdrawer)?;
let lp_addr = deps.api.addr_validate(&msg.lp_address)?;
// withdrawer is optional on instantiation; can be set later
if let Some(addr) = msg.withdrawer {
WITHDRAWER.save(deps.storage, &deps.api.addr_validate(&addr)?)?;
resp = resp.add_attribute("withdrawer", addr.to_string());
};

WITHDRAWER.save(deps.storage, &withdrawer)?;
let lp_addr = deps.api.addr_validate(&msg.lp_address)?;
LP_ADDRESS.save(deps.storage, &lp_addr)?;

Ok(Response::default()
.add_attribute("method", "instantiate")
.add_attribute("withdrawer", withdrawer)
.add_attribute("lp_address", lp_addr))
Ok(resp.add_attribute("lp_address", lp_addr))
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down Expand Up @@ -68,8 +70,14 @@ fn try_withdraw_liquidity(
) -> Result<Response, ContractError> {
deps.api.debug("WASMDEBUG: withdrawing liquidity");

// withdrawer has to be set for initiating liquidity withdrawal
let withdrawer = if let Some(addr) = WITHDRAWER.may_load(deps.storage)? {
addr
} else {
return Err(ContractError::NoWithdrawerError {})
};

// we validate who is initiating the liquidity removal
let withdrawer = WITHDRAWER.load(deps.storage)?;
if withdrawer != info.sender {
return Err(ContractError::Unauthorized {});
}
Expand All @@ -96,6 +104,7 @@ fn try_withdraw_liquidity(

Ok(Response::default()
.add_attribute("method", "try_withdraw")
.add_attribute("lp_token_amount", liquidity_token_balance.balance)
.add_message(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: pair_info.liquidity_token.to_string(),
msg: to_binary(withdraw_msg)?,
Expand All @@ -109,8 +118,14 @@ pub fn try_withdraw_balances(
info: MessageInfo,
quantity: Option<Vec<Coin>>,
) -> Result<Response, ContractError> {
// withdrawer has to be set for initiating balance withdrawal
let withdrawer = if let Some(addr) = WITHDRAWER.may_load(deps.storage)? {
addr
} else {
return Err(ContractError::NoWithdrawerError {})
};

// Check if the sender is the withdrawer
let withdrawer = WITHDRAWER.load(deps.storage)?;
if info.sender != withdrawer {
return Err(ContractError::Unauthorized {});
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/holder/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ pub enum ContractError {
#[error("Unauthorized")]
Unauthorized {},

#[error("Initial withdrawer is required")]
NoInitialWithdrawer {},
#[error("No withdrawer address configured")]
NoWithdrawerError {},
}
6 changes: 3 additions & 3 deletions contracts/holder/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use cosmwasm_std::{Addr, Binary, Coin};
pub struct InstantiateMsg {
/// A withdrawer is the only authorized address that can withdraw
/// from the contract. Anyone can instantiate the contract.
pub withdrawer: String,
pub withdrawer: Option<String>,
pub lp_address: String,
}

#[cw_serde]
pub struct PresetHolderFields {
pub withdrawer: String,
pub withdrawer: Option<String>,
pub holder_code: u64,
pub label: String,
}
Expand Down Expand Up @@ -40,7 +40,7 @@ pub enum ExecuteMsg {
#[derive(QueryResponses)]
pub enum QueryMsg {
// Queries the withdrawer address
#[returns(Addr)]
#[returns(Option<Addr>)]
Withdrawer {},
#[returns(Addr)]
LpAddress {},
Expand Down
15 changes: 13 additions & 2 deletions contracts/holder/src/suite_tests/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Default for SuiteBuilder {
fn default() -> Self {
Self {
instantiate: InstantiateMsg {
withdrawer: DEFAULT_WITHDRAWER.to_string(),
withdrawer: Some(DEFAULT_WITHDRAWER.to_string()),
lp_address: "stablepairpool".to_string(),
},
app: App::default(),
Expand All @@ -33,7 +33,7 @@ impl Default for SuiteBuilder {
}

impl SuiteBuilder {
pub fn with_withdrawer(mut self, addr: String) -> Self {
pub fn with_withdrawer(mut self, addr: Option<String>) -> Self {
self.instantiate.withdrawer = addr;
self
}
Expand Down Expand Up @@ -68,6 +68,17 @@ impl SuiteBuilder {

// actions
impl Suite {
pub fn withdraw_liquidity(&mut self, caller: &str) -> AppResponse {
self.app
.execute_contract(
Addr::unchecked(caller),
self.holder.clone(),
&ExecuteMsg::WithdrawLiquidity { },
&[],
)
.unwrap()
}

/// sends a message on caller's behalf to withdraw a specified amount of tokens
pub fn withdraw_tokens(&mut self, caller: &str, quantity: Vec<Coin>) -> AppResponse {
self.app
Expand Down
22 changes: 21 additions & 1 deletion contracts/holder/src/suite_tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn test_instantiate_and_query_withdrawer() {
#[should_panic(expected = "Invalid input: address not normalized")]
fn test_instantiate_invalid_withdrawer() {
SuiteBuilder::default()
.with_withdrawer("0Oo0Oo".to_string())
.with_withdrawer(Some("0Oo0Oo".to_string()))
.build();
}

Expand Down Expand Up @@ -123,3 +123,23 @@ fn test_fund_single_and_withdraw_too_big_single_denom() {

suite.withdraw_tokens(DEFAULT_WITHDRAWER, coins(100, "statom"));
}

#[test]
#[should_panic(expected = "No withdrawer address configured")]
fn test_withdraw_liquidity_no_withdrawer() {
let mut suite = SuiteBuilder::default()
.with_withdrawer(None)
.build();

suite.withdraw_liquidity(DEFAULT_WITHDRAWER);
}

#[test]
#[should_panic(expected = "No withdrawer address configured")]
fn test_withdraw_balances_no_withdrawer() {
let mut suite = SuiteBuilder::default()
.with_withdrawer(None)
.build();

suite.withdraw_tokens(DEFAULT_WITHDRAWER, coins(100, "statom"));
}
2 changes: 1 addition & 1 deletion contracts/lper/src/suite_test/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ impl Default for SuiteBuilder {
whitelist: vec!["contract9".to_string()],
},
holder_instantiate: covenant_holder::msg::InstantiateMsg {
withdrawer: CREATOR_ADDR.to_string(),
withdrawer: Some(CREATOR_ADDR.to_string()),
// deterministic based on instantiate flow
lp_address: "contract7".to_string(),
},
Expand Down