Skip to content

Commit

Permalink
wip: account for claimed rewards
Browse files Browse the repository at this point in the history
  • Loading branch information
emidev98 committed Feb 6, 2024
1 parent 9c5943c commit 21288b4
Show file tree
Hide file tree
Showing 15 changed files with 282 additions and 135 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
node_modules
# Build results
/target
/artifacts
artifacts
# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327)
.cargo-ok

Expand All @@ -21,6 +21,7 @@ node_modules
# Metadata from deployments
scripts/.oracle_address.log
scripts/.hub_address.log

scripts/.lp-hub-addr.log
scripts/.lp-hub-code-id.log
# Code coverage file
lcov.info
11 changes: 2 additions & 9 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,7 @@ docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
${image}:0.14.0
"""
[tasks.store-code]
script = """
ts-node ./scripts/store-code.ts
rm -rf scripts/artifacts
mv artifacts/ scripts/
"""

[tasks.migrate-contracts]
script = """
ts-node ./scripts/execute-migrate-contracts.ts
"""
26 changes: 11 additions & 15 deletions contracts/alliance-lp-hub/src/astro_models.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Decimal, Uint128};
use cw20::Cw20ReceiveMsg;
use cw_asset::AssetInfo;

#[cw_serde]
pub enum ExecuteAstroMsg {
Expand Down Expand Up @@ -40,20 +39,27 @@ pub enum QueryAstroMsg {
#[returns(Vec<RewardInfo>)]
RewardInfo { lp_token: String },
/// PendingToken returns the amount of rewards that can be claimed by an account that deposited a specific LP token in a generator
#[returns(Vec<Asset>)]
#[returns(Vec<PendingAssetRewards>)]
PendingRewards { lp_token: String, user: String },
/// Deposit returns the LP token amount deposited in a specific generator
#[returns(Uint128)]
Deposit { lp_token: String, user: String },
}

#[cw_serde]
pub struct Asset {
pub struct PendingAssetRewards {
/// Information about an asset stored in a [`AssetInfo`] struct
pub info: AssetInfo,
pub info: AstroAssetInfo,
/// A token amount
pub amount: Uint128,
}
#[cw_serde]
#[derive(Hash, Eq)]
pub enum AstroAssetInfo {
/// Non-native Token
Token { contract_addr: Addr },
/// Native token
NativeToken { denom: String },
}

#[cw_serde]
pub struct RewardInfo {
Expand Down Expand Up @@ -82,13 +88,3 @@ pub enum AstroRewardType {
next_update_ts: u64,
},
}

/// This enum describes available Token types.
#[cw_serde]
#[derive(Hash, Eq)]
pub enum AstroAssetInfo {
/// Non-native Token
Token { contract_addr: Addr },
/// Native token
NativeToken { denom: String },
}
100 changes: 41 additions & 59 deletions contracts/alliance-lp-hub/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use crate::{
astro_models::{Cw20Msg, ExecuteAstroMsg, QueryAstroMsg, RewardInfo},
astro_models::{Cw20Msg, ExecuteAstroMsg, PendingAssetRewards, QueryAstroMsg, RewardInfo},
helpers::{is_controller, is_governance},
models::{
from_string_to_asset_info, AstroClaimRewardsPosition, Config, ExecuteMsg, InstantiateMsg,
ModifyAssetPair,
},
models::{from_string_to_asset_info, Config, ExecuteMsg, InstantiateMsg, ModifyAssetPair},
state::{
ASSET_REWARD_RATE, BALANCES, CONFIG, TEMP_BALANCE, TOTAL_BALANCES, UNCLAIMED_REWARDS,
USER_ASSET_REWARD_RATE, VALIDATORS, WHITELIST,
Expand All @@ -20,14 +17,18 @@ use alliance_protocol::{
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_json_binary, Addr, BankMsg, Binary, Coin as CwCoin, CosmosMsg, Decimal, DepsMut, Empty, Env,
MessageInfo, Order, Reply, Response, StdError, StdResult, Storage, SubMsg, Uint128, WasmMsg,
to_json_binary, Addr, BankMsg, Binary, Coin as CwCoin, Coins, CosmosMsg, Decimal, DepsMut,
Empty, Env, MessageInfo, Order, Reply, Response, StdError, StdResult, Storage, SubMsg, Uint128,
WasmMsg,
};
use cw2::set_contract_version;
use cw20::Cw20ExecuteMsg;
use cw_asset::{Asset, AssetInfo, AssetInfoKey};
use cw_utils::parse_instantiate_response_data;
use std::{collections::HashSet, env, str::FromStr};
use std::{
collections::{HashMap, HashSet},
str::FromStr,
};
use terra_proto_rs::{
alliance::alliance::{MsgClaimDelegationRewards, MsgDelegate, MsgRedelegate, MsgUndelegate},
cosmos::base::v1beta1::Coin,
Expand Down Expand Up @@ -141,14 +142,6 @@ fn modify_asset(
let mut attrs = vec![("action".to_string(), "modify_asset".to_string())];

for asset in assets {
let reward_asset_info_key = match asset.reward_asset_info {
Some(reward_asset_info) => AssetInfoKey::from(reward_asset_info),
None => {
return Err(ContractError::MissingRewardAsset(
asset.asset_info.to_string(),
))
}
};
if asset.delete {
let asset_key = AssetInfoKey::from(asset.asset_info.clone());
WHITELIST.remove(deps.storage, asset_key.clone());
Expand All @@ -158,15 +151,7 @@ fn modify_asset(
]);
} else {
let asset_key = AssetInfoKey::from(asset.asset_info.clone());

WHITELIST.save(deps.storage, asset_key.clone(), &Decimal::zero())?;
ASSET_REWARD_RATE.update(
deps.storage,
(asset_key, reward_asset_info_key),
|asset_reward_rate| -> StdResult<_> {
Ok(asset_reward_rate.unwrap_or(Decimal::zero()))
},
)?;
WHITELIST.save(deps.storage, asset_key.clone(), &Decimal::new(asset.asset_distribution))?;
attrs.extend_from_slice(&[("asset".to_string(), asset.asset_info.to_string())]);
}
}
Expand Down Expand Up @@ -378,7 +363,7 @@ fn unstake(
user: env.contract.address.to_string(),
},
)
.unwrap_or_default();
.unwrap();

// If there are enough tokens staked in astro incentives,
// it means that we should withdraw tokens from astro
Expand Down Expand Up @@ -761,7 +746,7 @@ fn _update_astro_rewards(
let mut lp_tokens_list: Vec<String> = vec![];

for lp_token in whitelist {
let pending_rewards: Vec<Asset> = deps
let pending_rewards: Vec<PendingAssetRewards> = deps
.querier
.query_wasm_smart(
astro_incentives.to_string(),
Expand Down Expand Up @@ -1055,51 +1040,48 @@ fn reply_claim_astro_rewards(
));
}

// In the list of attributes we need to find the **claimed_positions**,
// and group all the **claimed_reward** for each claimed position.
let mut astro_claims: Vec<AstroClaimRewardsPosition> = vec![];
let mut astro_claim = AstroClaimRewardsPosition::default();
let mut count_claim_position = true;
// Map the event attributes to a hashmap to make it easier
// to group the rewards by the claimed position and then
// account for the rewards.
let mut astro_claims: HashMap<String, Coins> = HashMap::new();
let mut current_position: Option<String> = None;
for attr in event.attributes.iter() {
if attr.key == "claimed_position" && count_claim_position {
astro_claim = AstroClaimRewardsPosition::default();
astro_claim.deposited_asset = attr.value.clone();
count_claim_position = false;
}

if attr.key == "claimed_reward" {
let coin = CwCoin::from_str(&attr.value)?;
astro_claim.rewards.add(coin)?;
}

if attr.key == "claimed_reward" && !count_claim_position {
astro_claims.push(astro_claim.clone());
count_claim_position = true
match attr.key.as_str() {
"claimed_position" => {
current_position = Some(attr.value.clone());
astro_claims.entry(attr.value.clone()).or_default();
}
"claimed_reward" => {
if let Some(position) = &current_position {
if let Some(astro_claim) = astro_claims.get_mut(position) {
let coin = CwCoin::from_str(&attr.value)?;
astro_claim.add(coin)?;
}
}
}
_ => {}
}
}

// Given the claimed rewards account them to the state of the contract
// dividing the reward_amount per total_lp_staked summing the already
// accounted asset_reward_rate.
for claim in astro_claims {
let deposit_asset_key = from_string_to_asset_info(claim.deposited_asset)?;
for (deposited_asset, claim) in astro_claims {
let deposit_asset_key = from_string_to_asset_info(deposited_asset)?;
let total_lp_staked = TOTAL_BALANCES.load(deps.storage, deposit_asset_key.clone())?;
let total_lp_staked = Decimal::from_atomics(total_lp_staked, 0)?;

for reward in claim.rewards {
for reward in claim {
let reward_asset_key = from_string_to_asset_info(reward.denom)?;
let reward_ammount = Decimal::from_atomics(reward.amount, 0)?;
let mut asset_reward_rate = Decimal::zero();
let asset_reward_rate_key = (deposit_asset_key.clone(), reward_asset_key);
let mut asset_reward_rate = ASSET_REWARD_RATE
.load(deps.storage, asset_reward_rate_key.clone())
.unwrap_or_default();

ASSET_REWARD_RATE.update(
deps.storage,
(deposit_asset_key.clone(), reward_asset_key),
|a| -> StdResult<_> {
asset_reward_rate = a.unwrap_or_default();
asset_reward_rate = (reward_ammount / total_lp_staked) + asset_reward_rate;
Ok(asset_reward_rate)
},
)?;
asset_reward_rate = (reward_ammount / total_lp_staked) + asset_reward_rate;

ASSET_REWARD_RATE.save(deps.storage, asset_reward_rate_key, &asset_reward_rate)?;
}
}

Expand Down
23 changes: 4 additions & 19 deletions contracts/alliance-lp-hub/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use alliance_protocol::{
error::ContractError,
};
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Coins, Uint128};
use cosmwasm_std::{Addr, Uint128};
use cw20::Cw20ReceiveMsg;
use cw_asset::{Asset, AssetInfo, AssetInfoKey};
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;

pub type AssetDenom = String;

Expand Down Expand Up @@ -65,21 +65,12 @@ pub enum ExecuteMsg {

#[cw_serde]
pub struct ModifyAssetPair {
pub asset_distribution: Uint128,
pub asset_info: AssetInfo,
pub reward_asset_info: Option<AssetInfo>,
pub delete: bool,
}

impl ModifyAssetPair {
pub fn new(asset_info: AssetInfo, reward_asset_info: Option<AssetInfo>, delete: bool) -> Self {
ModifyAssetPair {
asset_info,
reward_asset_info,
delete,
}
}
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
Expand Down Expand Up @@ -110,7 +101,7 @@ pub enum QueryMsg {
#[returns(Vec<StakedBalanceRes>)]
TotalStakedBalances {},
}
pub type WhitelistedAssetsResponse = HashMap<AssetDenom, Vec<AssetInfo>>;
pub type WhitelistedAssetsResponse = Vec<AssetInfo>;

#[cw_serde]
pub struct AllPendingRewardsQuery {
Expand Down Expand Up @@ -142,12 +133,6 @@ pub struct StakedBalanceRes {
pub balance: Uint128,
}

#[derive(Clone, Default)]
pub struct AstroClaimRewardsPosition {
pub deposited_asset: String,
pub rewards: Coins,
}

pub fn from_string_to_asset_info(denom: String) -> Result<AssetInfoKey, ContractError> {
if denom.starts_with("ibc/") || denom.starts_with("factory/") {
let asset_info = AssetInfoKey::from(AssetInfo::Native(denom));
Expand Down
21 changes: 12 additions & 9 deletions contracts/alliance-lp-hub/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use crate::models::{
AllPendingRewardsQuery, AllStakedBalancesQuery, AssetQuery, PendingRewardsRes, QueryMsg,
StakedBalanceRes, WhitelistedAssetsResponse,
StakedBalanceRes
};
use alliance_protocol::alliance_oracle_types::EmissionsDistribution;
use alliance_protocol::signed_decimal::{Sign, SignedDecimal};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{to_json_binary, Binary, Decimal, Deps, Env, Order, StdResult, Uint128};
use cw_asset::{AssetInfo, AssetInfoKey, AssetInfoUnchecked};
use std::collections::HashMap;

use crate::state::{
ASSET_REWARD_RATE, BALANCES, CONFIG, TOTAL_BALANCES, UNCLAIMED_REWARDS, USER_ASSET_REWARD_RATE,
Expand Down Expand Up @@ -44,13 +43,13 @@ fn get_validators(deps: Deps) -> StdResult<Binary> {

fn get_whitelisted_assets(deps: Deps) -> StdResult<Binary> {
let whitelist = WHITELIST.range(deps.storage, None, None, Order::Ascending);
let mut res: WhitelistedAssetsResponse = HashMap::new();
let mut res: Vec<AssetInfo> = vec![];

for item in whitelist {
let (key, _) = item?;
let asset = key.check(deps.api, None)?;

res.entry(asset.to_string()).or_default().push(asset)
res.push(asset)
}

to_json_binary(&res)
Expand Down Expand Up @@ -89,11 +88,15 @@ fn get_pending_rewards(deps: Deps, asset_query: AssetQuery) -> StdResult<Binary>
let deposit_asset = AssetInfoKey::from(asset_query.deposit_asset.clone());

let key = (addr.clone(), deposit_asset.clone(), reward_asset.clone());
let user_reward_rate = USER_ASSET_REWARD_RATE.load(deps.storage, key)?;

let asset_reward_rate =
ASSET_REWARD_RATE.load(deps.storage, (deposit_asset.clone(), reward_asset.clone()))?;
let user_balance = BALANCES.load(deps.storage, (addr.clone(), deposit_asset.clone()))?;
let user_reward_rate = USER_ASSET_REWARD_RATE
.load(deps.storage, key)
.unwrap_or_default();
let asset_reward_rate = ASSET_REWARD_RATE
.load(deps.storage, (deposit_asset.clone(), reward_asset.clone()))
.unwrap_or_default();
let user_balance = BALANCES
.load(deps.storage, (addr.clone(), deposit_asset.clone()))
.unwrap_or_default();
let unclaimed_rewards = UNCLAIMED_REWARDS
.load(deps.storage, (addr, deposit_asset, reward_asset))
.unwrap_or_default();
Expand Down
1 change: 0 additions & 1 deletion contracts/alliance-lp-hub/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub const ASSET_REWARD_RATE: Map<(AssetInfoKey, AssetInfoKey), Decimal> =
// - Addr: is the address of the user,
// - AssetInfoKey: is the asset that is being deposited,
// - AssetInfoKey: is the asset that is being rewarded,
// - Decimal: is the reward rate,
pub const USER_ASSET_REWARD_RATE: Map<(Addr, AssetInfoKey, AssetInfoKey), Decimal> =
Map::new("user_asset_reward_rate");

Expand Down
Loading

0 comments on commit 21288b4

Please sign in to comment.