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

feat(incentives): enforce max gas limit on token transfers #434

Merged
merged 4 commits into from
Oct 28, 2024
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
26 changes: 13 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ thiserror = "1.0"
itertools = "0.12"
cosmwasm-schema = "1.5"
cw-utils = "1"
astroport = { path = "./packages/astroport", version = "5.6.0" }
astroport = { path = "./packages/astroport", version = "5.7.0" }

[profile.release]
opt-level = "z"
Expand Down
2 changes: 1 addition & 1 deletion contracts/tokenomics/incentives/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "astroport-incentives"
version = "1.2.0"
version = "1.3.0"
authors = ["Astroport"]
edition = "2021"
description = "Astroport Incentives Contract distributing rewards to LP stakers"
Expand Down
29 changes: 25 additions & 4 deletions contracts/tokenomics/incentives/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use astroport::asset::{
use astroport::common::{claim_ownership, drop_ownership_proposal, propose_new_owner};
use astroport::factory;
use astroport::factory::PairType;
use astroport::incentives::{Cw20Msg, ExecuteMsg, IncentivizationFeeInfo, RewardType};
use astroport::incentives::{
Cw20Msg, ExecuteMsg, IncentivizationFeeInfo, RewardType, TOKEN_TRANSFER_GAS_LIMIT,
};

use crate::error::ContractError;
use crate::state::{
Expand Down Expand Up @@ -61,7 +63,8 @@ pub fn execute(
.collect_vec();

// Compose response. Return early in case of error
let response = claim_rewards(deps.storage, None, env, &info.sender, mut_tuples)?;
let config = CONFIG.load(deps.storage)?;
let response = claim_rewards(deps.storage, &config, env, &info.sender, mut_tuples)?;

// Save updates in state
for (lp_asset, pool_info, user_pos) in tuples {
Expand Down Expand Up @@ -121,6 +124,7 @@ pub fn execute(
generator_controller,
guardian,
incentivization_fee_info,
token_transfer_gas_limit,
} => update_config(
deps,
info,
Expand All @@ -129,6 +133,7 @@ pub fn execute(
generator_controller,
guardian,
incentivization_fee_info,
token_transfer_gas_limit,
),
ExecuteMsg::UpdateBlockedTokenslist { add, remove } => {
update_blocked_pool_tokens(deps, env, info, add, remove)
Expand Down Expand Up @@ -193,7 +198,7 @@ fn deposit(

let response = claim_rewards(
deps.storage,
Some(config.vesting_contract),
&config,
env,
&staker,
vec![(&maybe_lp.info, &mut pool_info, &mut user_info)],
Expand Down Expand Up @@ -230,9 +235,10 @@ fn withdraw(
} else {
let mut pool_info = PoolInfo::load(deps.storage, &lp_token_asset)?;

let config = CONFIG.load(deps.storage)?;
let response = claim_rewards(
deps.storage,
None,
&config,
env,
&info.sender,
vec![(&lp_token_asset, &mut pool_info, &mut user_info)],
Expand Down Expand Up @@ -372,6 +378,7 @@ fn set_tokens_per_second(
Ok(Response::new().add_attribute("action", "set_tokens_per_second"))
}

#[allow(clippy::too_many_arguments)]
fn update_config(
deps: DepsMut,
info: MessageInfo,
Expand All @@ -380,6 +387,7 @@ fn update_config(
generator_controller: Option<String>,
guardian: Option<String>,
incentivization_fee_info: Option<IncentivizationFeeInfo>,
token_transfer_gas_limit: Option<u64>,
) -> Result<Response, ContractError> {
let mut config = CONFIG.load(deps.storage)?;

Expand Down Expand Up @@ -439,6 +447,19 @@ fn update_config(
config.incentivization_fee_info = Some(new_info);
}

if let Some(token_transfer_gas_limit) = token_transfer_gas_limit {
ensure!(
TOKEN_TRANSFER_GAS_LIMIT.contains(&token_transfer_gas_limit),
StdError::generic_err("Invalid token transfer gas limit")
);

attrs.push(attr(
"new_token_transfer_gas_limit",
token_transfer_gas_limit.to_string(),
));
config.token_transfer_gas_limit = Some(token_transfer_gas_limit);
}

CONFIG.save(deps.storage, &config)?;

Ok(Response::new().add_attributes(attrs))
Expand Down
1 change: 1 addition & 0 deletions contracts/tokenomics/incentives/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub fn instantiate(
vesting_contract: deps.api.addr_validate(&msg.vesting_contract)?,
guardian: addr_opt_validate(deps.api, &msg.guardian)?,
incentivization_fee_info: msg.incentivization_fee_info,
token_transfer_gas_limit: None,
},
)?;
ACTIVE_POOLS.save(deps.storage, &vec![])?;
Expand Down
2 changes: 1 addition & 1 deletion contracts/tokenomics/incentives/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result<Response, Contra

match contract_version.contract.as_ref() {
"astroport-incentives" => match contract_version.version.as_ref() {
"1.0.0" | "1.0.1" | "1.1.0" => {}
"1.0.0" | "1.0.1" | "1.1.0" | "1.2.0" => {}
_ => return Err(ContractError::MigrationError {}),
},
_ => return Err(ContractError::MigrationError {}),
Expand Down
9 changes: 6 additions & 3 deletions contracts/tokenomics/incentives/src/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ pub const POST_TRANSFER_REPLY_ID: u64 = 1;
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
match msg {
// Caller context: either utils:claim_rewards() or utils:remove_reward_from_pool().
// If cw20 token reverts the transfer, we bypass it silently.
// This can happen in abnormal situations when cw20 contract was tweaked and broken.
// Caller context: either utils:claim_rewards(),
// utils:claim_orphaned_rewards() or utils:remove_reward_from_pool().
// If cw20 or token factory token with bank hook reverts the transfer,
// we bypass it silently.
// This error also can be reached if token transfer hits gas limit
// (see astroport/incentives.rs:Config:token_transfer_gas_limit).
Reply {
id: POST_TRANSFER_REPLY_ID,
result: SubMsgResult::Err(err_msg),
Expand Down
34 changes: 18 additions & 16 deletions contracts/tokenomics/incentives/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::state::{
/// If vesting_contract is None this function reads config from state and gets vesting address.
pub fn claim_rewards(
storage: &dyn Storage,
vesting_contract: Option<Addr>,
config: &Config,
env: Env,
user: &Addr,
pool_tuples: Vec<(&AssetInfo, &mut PoolInfo, &mut UserInfo)>,
Expand Down Expand Up @@ -71,20 +71,18 @@ pub fn claim_rewards(
.into_iter()
.map(|(info, assets)| {
let amount: Uint128 = assets.into_iter().map(|asset| asset.amount).sum();
info.with_balance(amount)
.into_submsg(user, Some((ReplyOn::Error, POST_TRANSFER_REPLY_ID)))
info.with_balance(amount).into_submsg(
user,
Some((ReplyOn::Error, POST_TRANSFER_REPLY_ID)),
config.token_transfer_gas_limit,
)
})
.collect::<StdResult<Vec<_>>>()?;

// Claim Astroport rewards
if !protocol_reward_amount.is_zero() {
let vesting_contract = if let Some(vesting_contract) = vesting_contract {
vesting_contract
} else {
CONFIG.load(storage)?.vesting_contract
};
messages.push(SubMsg::new(wasm_execute(
vesting_contract,
&config.vesting_contract,
&vesting::ExecuteMsg::Claim {
recipient: Some(user.to_string()),
amount: Some(protocol_reward_amount),
Expand Down Expand Up @@ -366,9 +364,11 @@ pub fn remove_reward_from_pool(
// Send unclaimed rewards
if !unclaimed.is_zero() {
deps.api.addr_validate(&receiver)?;
let transfer_msg = reward_asset
.with_balance(unclaimed)
.into_submsg(receiver, Some((ReplyOn::Error, POST_TRANSFER_REPLY_ID)))?;
let transfer_msg = reward_asset.with_balance(unclaimed).into_submsg(
receiver,
Some((ReplyOn::Error, POST_TRANSFER_REPLY_ID)),
config.token_transfer_gas_limit,
)?;
response = response.add_submessage(transfer_msg);
}

Expand Down Expand Up @@ -423,8 +423,7 @@ pub fn is_pool_registered(
))
})
.map(|resp| {
// Eventually resp.liquidity_token will become just a String once token factory LP tokens are implemented
if resp.liquidity_token.as_str() == lp_token_addr {
if resp.liquidity_token == lp_token_addr {
Ok(())
} else {
Err(StdError::generic_err(format!(
Expand Down Expand Up @@ -474,8 +473,11 @@ pub fn claim_orphaned_rewards(

attrs.push(attr("claimed_orphaned_reward", reward_asset.to_string()));

let transfer_msg = reward_asset
.into_submsg(&receiver, Some((ReplyOn::Error, POST_TRANSFER_REPLY_ID)))?;
let transfer_msg = reward_asset.into_submsg(
&receiver,
Some((ReplyOn::Error, POST_TRANSFER_REPLY_ID)),
config.token_transfer_gas_limit,
)?;
messages.push(transfer_msg);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,7 @@ fn test_astro_protocol_reward_if_denom_changed() {
generator_controller: None,
guardian: None,
incentivization_fee_info: None,
token_transfer_gas_limit: None,
};
helper
.app
Expand Down Expand Up @@ -2055,13 +2056,15 @@ fn test_update_config() {
fee_receiver: TestAddr::new("new_fee_receiver"),
fee: coin(1000, "uusd"),
};
let new_gas_limit = 800_000;

let msg = ExecuteMsg::UpdateConfig {
astro_token: Some(AssetInfo::native("new_astro")),
vesting_contract: Some(new_vesting.to_string()),
generator_controller: Some(new_generator_controller.to_string()),
guardian: Some(new_guardian.to_string()),
incentivization_fee_info: Some(new_incentivization_fee_info.clone()),
token_transfer_gas_limit: Some(new_gas_limit),
};

let err = helper
Expand Down Expand Up @@ -2090,6 +2093,7 @@ fn test_update_config() {
config.incentivization_fee_info.unwrap(),
new_incentivization_fee_info
);
assert_eq!(config.token_transfer_gas_limit.unwrap(), new_gas_limit);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion packages/astroport/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "astroport"
version = "5.6.0"
version = "5.7.0"
authors = ["Astroport"]
edition = "2021"
description = "Common Astroport types, queriers and other utils"
Expand Down
Loading
Loading