Skip to content

Commit

Permalink
Instant LP Unbonding audit fixes (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
betterclever authored Aug 14, 2023
2 parents ae35bae + 1c78253 commit ac07347
Show file tree
Hide file tree
Showing 23 changed files with 336 additions and 79 deletions.
14 changes: 7 additions & 7 deletions artifacts/checksums.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
4ac1e33a038ded0ae9b6972d6824e2aa3aa95ed66265e1516c6aafb0ac11d3a7 dexter_keeper.wasm
ee15468b8052bc9978a1ebb1a9fe9ed0473eab8a4d3f0a0542ac6089f2780f59 dexter_multi_staking.wasm
ab57be7665839cb36168a87a5bfaf2b5c819c4a19ad7ddcadd67667f012908bc dexter_router.wasm
42c0aa3e0a9e65bbb271fdac0bcd0022ad0005ec033baf0773bfbc0108823090 dexter_vault.wasm
f49d42485d6fdf9d5852356b57c48e512756b4c976e35e8702913ec70b12bd8c lp_token.wasm
25178e81e6b0763e019ba3bc1989d8ff0717a33e73c2d1be3ad7bd156e4c6b43 stable_pool.wasm
fe53791ac1f8e64c6f47f84924d955f9edd93b8be01cfa5c6394ff66e4fc5b55 weighted_pool.wasm
dba4b05f5c44ae0018e600af25e7d846ab9951cec465677f435731f691f87ee8 dexter_keeper.wasm
1e893c47829d608b57e39c08441b4f3166f0526761e89f38130be0df1815df08 dexter_multi_staking.wasm
a0c4aef5aea5fd744e56881af4bed74701176172c02b07d5bc4b877be680ec73 dexter_router.wasm
49cb0521450576bf58bbf7c07eb3917960dc0b354c502d51a3904d7abfcfef08 dexter_vault.wasm
48ea4061c0080304e3bf20b01fb732923a662405d2711ebe46c7eb5e2af551b4 lp_token.wasm
8e6bc60198e3841c9df777b9c7b8b8df83177137505dd4f61412593b08a756dd stable_pool.wasm
2cd890107c1a87ab07b9dc227c303e3475bddc4f4633dbe929e7f66b9349b0b8 weighted_pool.wasm
14 changes: 7 additions & 7 deletions artifacts/checksums_intermediate.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
05971cc5fde5ecdef48e10858be09ce712302db909c645686d62df9a4d7cfd1c target/wasm32-unknown-unknown/release/dexter_router.wasm
2e704ea74a75284e164e6a24fee43d46aba2d931555c2201051e4b1792ccf3bc target/wasm32-unknown-unknown/release/dexter_vault.wasm
a0fd9298442f35d2dd63cf5e1e3c5f1a059e1ee289bd3d2930855203f4648f94 target/wasm32-unknown-unknown/release/lp_token.wasm
0cb092ed15824d9a8f16c2b158e01d46698e194e2f1bfacb7fd971433880b369 target/wasm32-unknown-unknown/release/stable_pool.wasm
ae0386688920a0c490079040da80a9d620f2ea2e1204e4cf160bb0f320389e8c target/wasm32-unknown-unknown/release/weighted_pool.wasm
175af42a8c149a352c12831744f0ea6a9fc27e5820ee343a6ba05b97833165c0 target/wasm32-unknown-unknown/release/dexter_keeper.wasm
d1999deb7e766ae25f6b07365d5e351f5cc3c7a751deec2c5d50ea6072b580ec target/wasm32-unknown-unknown/release/dexter_multi_staking.wasm
06358078df042cae3f0709ed6e4ba0ac1dd4519b006474778ba710389f2fd652 target/wasm32-unknown-unknown/release/dexter_keeper.wasm
6c2001da0d68530716f88273688e0df43bebe9394a4f2e3f1fd2b85a55cba207 target/wasm32-unknown-unknown/release/dexter_multi_staking.wasm
d1ec972791b3d9fe5bbadf960e287ae13caffc78d821b5e0f4a1ffacf0cc9d8b target/wasm32-unknown-unknown/release/dexter_router.wasm
dc152ea6e8dccee6e524ec270b4991ff2275edb5c0046cc77551eb73c8b81ba7 target/wasm32-unknown-unknown/release/dexter_vault.wasm
dfc3f668e654ec74f3ec890322cf059078cf6910a59106359321c1d0790e0e88 target/wasm32-unknown-unknown/release/lp_token.wasm
613e0ebb3865b2db279f192ee01205a37465cf8394b86a14f683e494ca826fc3 target/wasm32-unknown-unknown/release/stable_pool.wasm
9f2f60a993dc689fd6a87963b0038f9afe1b0846278a0a50280dd856e1d8807c target/wasm32-unknown-unknown/release/weighted_pool.wasm
Binary file modified artifacts/dexter_keeper.wasm
Binary file not shown.
Binary file modified artifacts/dexter_multi_staking.wasm
Binary file not shown.
Binary file modified artifacts/dexter_router.wasm
Binary file not shown.
Binary file modified artifacts/dexter_vault.wasm
Binary file not shown.
Binary file modified artifacts/lp_token.wasm
Binary file not shown.
Binary file modified artifacts/stable_pool.wasm
Binary file not shown.
Binary file modified artifacts/weighted_pool.wasm
Binary file not shown.
18 changes: 17 additions & 1 deletion contracts/keeper/schema/dexter-keeper.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,26 @@
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
"description": "The amount of LP tokens to exit",
"allOf": [
{
"$ref": "#/definitions/Uint128"
}
]
},
"lp_token_address": {
"description": "Contract address of the LP token",
"type": "string"
},
"min_assets_received": {
"description": "Slippage protection",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Asset"
}
}
},
"additionalProperties": false
Expand Down
57 changes: 41 additions & 16 deletions contracts/keeper/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,15 @@ pub fn execute(
ExecuteMsg::ExitLPTokens {
lp_token_address,
amount,
min_assets_received
} => exit_lp_tokens(deps, env, info, lp_token_address, amount, min_assets_received),
min_assets_received,
} => exit_lp_tokens(
deps,
env,
info,
lp_token_address,
amount,
min_assets_received,
),
ExecuteMsg::SwapAsset {
offer_asset,
ask_asset_info,
Expand Down Expand Up @@ -175,7 +182,9 @@ fn withdraw(
}

// Send the funds to the recipient or to the owner if no recipient is specified
let recipient = deps.api.addr_validate(recipient.unwrap_or(config.owner).as_str())?;
let recipient = deps
.api
.addr_validate(recipient.unwrap_or(config.owner).as_str())?;
let transfer_msg = asset.create_transfer_msg(recipient.clone(), amount)?;

Ok(Response::new().add_message(transfer_msg).add_event(
Expand All @@ -196,9 +205,8 @@ fn create_dexter_exit_pool_msg(
) -> Result<CosmosMsg, ContractError> {
let recipient = env.contract.address.clone();

let config = CONFIG.load(deps.storage)?;
let pool_info: PoolInfo = deps.querier.query_wasm_smart(
config.vault_address.to_string(),
vault_address.to_string(),
&dexter::vault::QueryMsg::GetPoolByLpTokenAddress {
lp_token_addr: lp_token_address.to_string(),
},
Expand Down Expand Up @@ -283,6 +291,7 @@ fn swap_asset(
min_receive: Option<Uint128>,
) -> Result<Response, ContractError> {
let config = CONFIG.load(deps.storage)?;
let mut msgs: Vec<CosmosMsg> = vec![];

// Permission check
if info.sender != config.owner {
Expand All @@ -295,6 +304,29 @@ fn swap_asset(
return Err(ContractError::InsufficientBalance);
}

let mut funds_to_send = vec![];
// if we are swapping for a CW20 token, we need to approve the vault to spend the funds
match &offer_asset.info {
AssetInfo::Token { contract_addr } => {
let msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: contract_addr.to_string(),
msg: to_binary(&Cw20ExecuteMsg::IncreaseAllowance {
spender: config.vault_address.to_string(),
amount: offer_asset.amount,
// since they are happening in the same transaction, we only approve for 1 extra height
expires: Some(cw20::Expiration::AtHeight(env.block.height + 1)),
})?,
funds: vec![],
});

msgs.push(msg);
}
AssetInfo::NativeToken { denom } => {
let coin = Coin::new(offer_asset.amount.u128(), denom.clone());
funds_to_send.push(coin);
}
}

// Create a dexter swap message and return the swapped funds to the keeper itself
let swap_msg = dexter::vault::ExecuteMsg::Swap {
swap_request: SingleSwapRequest {
Expand All @@ -311,22 +343,15 @@ fn swap_asset(
max_spend: None,
};

let swap_send_funds = if let AssetInfo::NativeToken { denom } = &offer_asset.info {
vec![Coin {
denom: denom.clone(),
amount: offer_asset.amount,
}]
} else {
vec![]
};

let cosmos_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: config.vault_address.to_string(),
funds: swap_send_funds,
funds: funds_to_send,
msg: to_binary(&swap_msg)?,
});

Ok(Response::new().add_message(cosmos_msg).add_event(
msgs.push(cosmos_msg);

Ok(Response::new().add_messages(msgs).add_event(
Event::from_info(concatcp!(CONTRACT_NAME, "::swap_asset"), &info)
.add_attribute("pool_id", pool_id.to_string())
.add_attribute("offer_asset", offer_asset.to_string())
Expand Down
151 changes: 150 additions & 1 deletion contracts/keeper/tests/dexter-swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use dexter::{
vault::FeeInfo,
};

use crate::utils::assert_cw20_balance;
use crate::utils::{assert_cw20_balance, store_token_code};

mod utils;

Expand Down Expand Up @@ -51,9 +51,11 @@ fn test_exit_and_swap() {

let native_asset_precisions = vec![("uatom".to_string(), 6u8), ("uxprt".to_string(), 6u8)];

let lp_token_code_id: u64 = store_token_code(&mut app);
let (vault_addr, keeper_addr, pool_id, _pool_addr, lp_token_addr) =
utils::instantiate_contracts(
&mut app,
lp_token_code_id,
&owner,
&keeper_owner,
fee_info,
Expand Down Expand Up @@ -200,3 +202,150 @@ fn test_exit_and_swap() {
assert_eq!(uatom_balance.amount, Uint128::from(3000u64));
assert_eq!(uxprt_balance.amount, Uint128::from(9487846u64));
}


// Test the swap message for CW20 asset pools
#[test]
fn test_cw20_asset_swap() {
let owner: Addr = Addr::unchecked("owner".to_string());
let keeper_owner: Addr = Addr::unchecked("keeper_owner".to_string());
let alice_address: Addr = Addr::unchecked("alice".to_string());

let mut app = utils::mock_app(
owner.clone(),
vec![
Coin {
denom: "uatom".to_string(),
amount: uint128_with_precision!(100_000u128, 6),
},
],
);

// send uatom to alice
app.send_tokens(
owner.clone(),
alice_address.clone(),
&vec![
Coin {
denom: "uatom".to_string(),
amount: uint128_with_precision!(100u128, 6),
},
],
).unwrap();

let lp_token_code_id: u64 = store_token_code(&mut app);
// create a cw20 asset and pair it with uxprt
let cw20_asset = utils::instantiate_cw20_token(&mut app, &owner, lp_token_code_id, "TEST".to_string(), uint128_with_precision!(100_000u128, 6));

let fee_info = FeeInfo {
total_fee_bps: 30,
protocol_fee_percent: 20,
};

let asset_infos = vec![
AssetInfo::native_token("uatom".to_string()),
AssetInfo::token(cw20_asset.clone())
];

let native_asset_precisions = vec![("uatom".to_string(), 6u8)];

let (vault_addr, keeper_addr, pool_id, _pool_addr, _lp_token_addr) =
utils::instantiate_contracts(
&mut app,
lp_token_code_id,
&owner,
&keeper_owner,
fee_info,
asset_infos,
native_asset_precisions,
);

// mint some tokens for alice
let mint_msg = cw20::Cw20ExecuteMsg::Mint {
recipient: alice_address.clone().into(),
amount: uint128_with_precision!(1_000u128, 6),
};

app.execute_contract(owner.clone(), cw20_asset.clone(), &mint_msg, &[]).unwrap();


// join pool from alice
let join_msg = dexter::vault::ExecuteMsg::JoinPool {
pool_id,
recipient: None,
assets: Some(vec![
Asset::new_native("uatom".to_string(), uint128_with_precision!(50u128, 6)),
Asset::new_token(cw20_asset.clone(), uint128_with_precision!(50u128, 6)),
]),
min_lp_to_receive: None,
auto_stake: None,
};

// allow vault to spend Alice's CW20 tokens
let approve_msg = cw20::Cw20ExecuteMsg::IncreaseAllowance {
spender: vault_addr.clone().into(),
amount: uint128_with_precision!(50u128, 6),
expires: None,
};

app.execute_contract(alice_address.clone(), cw20_asset.clone(), &approve_msg, &[])
.unwrap();

// send the message
app.execute_contract(
alice_address.clone(),
vault_addr.clone(),
&join_msg,
&[
Coin {
denom: "uatom".to_string(),
amount: uint128_with_precision!(50u128, 6),
},
],
)
.unwrap();

// send some CW20 tokens from Alice to keeper contract
let send_msg = cw20::Cw20ExecuteMsg::Transfer {
recipient: keeper_addr.clone().into(),
amount: uint128_with_precision!(20u128, 6),
};

app.execute_contract(alice_address.clone(), cw20_asset.clone(), &send_msg, &[])
.unwrap();

// validate keeper CW20 balance
assert_cw20_balance(
&app,
&cw20_asset,
&keeper_addr,
uint128_with_precision!(20u128, 6),
);

// swap CW20 tokens for uatom in keeper
let swap_msg = dexter::keeper::ExecuteMsg::SwapAsset {
offer_asset: Asset::new_token(cw20_asset.clone(), uint128_with_precision!(5u128, 6)),
ask_asset_info: AssetInfo::native_token("uatom".to_string()),
min_ask_amount: None,
pool_id,
};

app.execute_contract(keeper_owner.clone(), keeper_addr.clone(), &swap_msg, &[]).unwrap();

// validate keeper CW20 balance is decreased
assert_cw20_balance(
&app,
&cw20_asset,
&keeper_addr,
Uint128::from(15003000u128),
);

// validate keeper uatom balance is increased
let uatom_balance = app
.wrap()
.query_balance(keeper_addr.clone(), "uatom".to_string())
.unwrap();

assert_eq!(uatom_balance.amount, Uint128::from(4533054u128));

}
Loading

0 comments on commit ac07347

Please sign in to comment.