Skip to content

Commit 28bc695

Browse files
Merge branch 'master' into fix_claim_account
2 parents 2c5f052 + 3e1e75c commit 28bc695

11 files changed

Lines changed: 277 additions & 81 deletions

File tree

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/omnipool/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-omnipool"
3-
version = "5.1.10"
3+
version = "5.1.11"
44
authors = ['GalacticCouncil']
55
edition = "2021"
66
license = "Apache-2.0"

pallets/omnipool/src/lib.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,12 +2103,23 @@ impl<T: Config> Pallet<T> {
21032103
.filter(|fee| fee.amount > 0) // filter out when we zero percentage is configured for fees
21042104
.collect();
21052105

2106-
let taken_fee_total: Balance = taken_fee_entries.iter().map(|fee| fee.amount).sum();
2106+
// Total fee taken as reported from the hook
2107+
let taken_fee_total: Balance = taken_fee_entries
2108+
.iter()
2109+
.try_fold(Balance::zero(), |acc, fee| acc.checked_add(fee.amount))
2110+
.ok_or(ArithmeticError::Overflow)?;
21072111

21082112
let asset_reserve = T::Currency::free_balance(asset, &account);
2109-
let diff = original_asset_reserve.saturating_sub(asset_reserve);
2110-
ensure!(diff <= allowed_amount, Error::<T>::FeeOverdraft);
2111-
ensure!(diff == taken_fee_total, Error::<T>::FeeOverdraft);
2113+
let actual_fee_taken = original_asset_reserve.saturating_sub(asset_reserve);
2114+
2115+
// We allowed `allowed_amount` as the max fee that can be taken by external sources
2116+
// To support Atokens, we need to allow a tolerance of 1 extra unit.
2117+
ensure!(
2118+
actual_fee_taken <= allowed_amount.saturating_add(Balance::one()),
2119+
Error::<T>::FeeOverdraft
2120+
);
2121+
// And the actual fee taken must be equal to the reported amount!
2122+
ensure!(actual_fee_taken == taken_fee_total, Error::<T>::FeeOverdraft);
21122123

21132124
let protocol_fee_amount = amount.saturating_sub(taken_fee_total);
21142125

pallets/omnipool/src/tests/buy.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,3 +1107,71 @@ fn buy_with_all_fees_and_extra_withdrawal_works() {
11071107
assert_eq!(initial_reserve, omnipool_200_reserve + buy_amount + fee_collector);
11081108
});
11091109
}
1110+
1111+
#[test]
1112+
fn buy_allows_tolerance_when_part_of_fee_is_taken() {
1113+
ExtBuilder::default()
1114+
.with_endowed_accounts(vec![
1115+
(Omnipool::protocol_account(), DAI, 1000 * ONE),
1116+
(Omnipool::protocol_account(), HDX, NATIVE_AMOUNT),
1117+
(LP2, 100, 2000 * ONE),
1118+
(LP3, 200, 2000 * ONE),
1119+
(LP1, 100, 1000 * ONE),
1120+
])
1121+
.with_registered_asset(100)
1122+
.with_registered_asset(200)
1123+
.with_asset_fee(Permill::from_percent(10))
1124+
.with_protocol_fee(Permill::from_percent(3))
1125+
.with_burn_fee(Permill::from_percent(50))
1126+
.with_on_trade_withdrawal(Permill::from_percent(100))
1127+
.with_on_trade_withdrawal_extra(Balance::one())
1128+
.with_initial_pool(FixedU128::from(1), FixedU128::from(1))
1129+
.with_token(100, FixedU128::one(), LP2, 2000 * ONE)
1130+
.with_token(200, FixedU128::one(), LP3, 2000 * ONE)
1131+
.build()
1132+
.execute_with(|| {
1133+
let buy_amount = 10 * ONE;
1134+
1135+
assert_ok!(Omnipool::buy(
1136+
RuntimeOrigin::signed(LP1),
1137+
200,
1138+
100,
1139+
buy_amount,
1140+
u128::MAX,
1141+
));
1142+
1143+
assert_asset_state!(
1144+
100,
1145+
AssetReserveState {
1146+
reserve: 2011585471818340,
1147+
hub_reserve: 1988481253239648,
1148+
shares: 2000000000000000,
1149+
protocol_shares: Balance::zero(),
1150+
cap: DEFAULT_WEIGHT_CAP,
1151+
tradable: Tradability::default(),
1152+
}
1153+
);
1154+
assert_asset_state!(
1155+
200,
1156+
AssetReserveState {
1157+
reserve: 1988888888888888,
1158+
hub_reserve: 2011173184357542,
1159+
shares: 2000 * ONE,
1160+
protocol_shares: Balance::zero(),
1161+
cap: DEFAULT_WEIGHT_CAP,
1162+
tradable: Tradability::default(),
1163+
}
1164+
);
1165+
1166+
assert_eq!(Tokens::free_balance(100, &LP1), 988414528181660);
1167+
assert_eq!(Tokens::free_balance(200, &LP1), buy_amount);
1168+
assert_eq!(Tokens::free_balance(200, &TRADE_FEE_COLLECTOR), 1111111111112);
1169+
assert_eq!(Tokens::free_balance(LRNA, &PROTOCOL_FEE_COLLECTOR), 172781201405);
1170+
1171+
// Account for 200 asset
1172+
let initial_reserve = 2000 * ONE;
1173+
let omnipool_200_reserve = Tokens::free_balance(200, &Omnipool::protocol_account());
1174+
let fee_collector = Tokens::free_balance(200, &TRADE_FEE_COLLECTOR);
1175+
assert_eq!(initial_reserve, omnipool_200_reserve + buy_amount + fee_collector);
1176+
});
1177+
}

pallets/omnipool/src/tests/mock.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ thread_local! {
8080
pub static WITHDRAWAL_FEE: RefCell<Permill> = const { RefCell::new(Permill::from_percent(0)) };
8181
pub static WITHDRAWAL_ADJUSTMENT: RefCell<(u32,u32, bool)> = const { RefCell::new((0u32,0u32, false)) };
8282
pub static ON_TRADE_WITHDRAWAL: RefCell<Permill> = const { RefCell::new(Permill::from_percent(0)) };
83+
pub static ON_TRADE_WITHDRAWAL_EXTRA: RefCell<Balance> = const { RefCell::new(0) };
8384
}
8485

8586
construct_runtime!(
@@ -280,6 +281,12 @@ impl Default for ExtBuilder {
280281
WITHDRAWAL_ADJUSTMENT.with(|v| {
281282
*v.borrow_mut() = (0, 0, false);
282283
});
284+
ON_TRADE_WITHDRAWAL.with(|v| {
285+
*v.borrow_mut() = Permill::from_percent(0);
286+
});
287+
ON_TRADE_WITHDRAWAL_EXTRA.with(|v| {
288+
*v.borrow_mut() = Balance::zero();
289+
});
283290

284291
Self {
285292
endowed_accounts: vec![
@@ -383,6 +390,11 @@ impl ExtBuilder {
383390
self
384391
}
385392

393+
pub fn with_on_trade_withdrawal_extra(self, extra: Balance) -> Self {
394+
ON_TRADE_WITHDRAWAL_EXTRA.with(|v| *v.borrow_mut() = extra);
395+
self
396+
}
397+
386398
pub fn with_token(
387399
mut self,
388400
asset_id: AssetId,
@@ -747,8 +759,9 @@ impl OmnipoolHooks<RuntimeOrigin, AccountId, AssetId, Balance> for MockHooks {
747759
) -> Result<Vec<Option<(Balance, AccountId)>>, Self::Error> {
748760
let percentage = ON_TRADE_WITHDRAWAL.with(|v| *v.borrow());
749761
let to_take = percentage.mul_floor(amount);
750-
<Tokens as MultiCurrency<AccountId>>::transfer(asset, &fee_account, &TRADE_FEE_COLLECTOR, to_take)?;
751-
Ok(vec![Some((to_take, TRADE_FEE_COLLECTOR))])
762+
let add_extra = ON_TRADE_WITHDRAWAL_EXTRA.with(|v| *v.borrow());
763+
<Tokens as MultiCurrency<AccountId>>::transfer(asset, &fee_account, &TRADE_FEE_COLLECTOR, to_take + add_extra)?;
764+
Ok(vec![Some((to_take + add_extra, TRADE_FEE_COLLECTOR))])
752765
}
753766

754767
fn consume_protocol_fee(

pallets/omnipool/src/tests/sell.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,3 +1061,72 @@ fn sell_with_all_fees_and_extra_withdrawal_works() {
10611061
assert_eq!(initial_reserve, omnipool_200_reserve + buy_amount + fee_collector);
10621062
});
10631063
}
1064+
1065+
#[test]
1066+
fn sell_allows_tolerance_when_part_of_fee_is_taken() {
1067+
ExtBuilder::default()
1068+
.with_endowed_accounts(vec![
1069+
(Omnipool::protocol_account(), DAI, 1000 * ONE),
1070+
(Omnipool::protocol_account(), HDX, NATIVE_AMOUNT),
1071+
(LP2, 100, 2000 * ONE),
1072+
(LP3, 200, 2000 * ONE),
1073+
(LP1, 100, 1000 * ONE),
1074+
])
1075+
.with_registered_asset(100)
1076+
.with_registered_asset(200)
1077+
.with_asset_fee(Permill::from_percent(10))
1078+
.with_protocol_fee(Permill::from_percent(3))
1079+
.with_burn_fee(Permill::from_percent(50))
1080+
.with_on_trade_withdrawal(Permill::from_percent(100))
1081+
.with_on_trade_withdrawal_extra(1)
1082+
.with_initial_pool(FixedU128::from(1), FixedU128::from(1))
1083+
.with_token(100, FixedU128::one(), LP2, 2000 * ONE)
1084+
.with_token(200, FixedU128::one(), LP3, 2000 * ONE)
1085+
.build()
1086+
.execute_with(|| {
1087+
let sell_amount = 50 * ONE;
1088+
let min_limit = 10 * ONE;
1089+
1090+
assert_ok!(Omnipool::sell(
1091+
RuntimeOrigin::signed(LP1),
1092+
100,
1093+
200,
1094+
sell_amount,
1095+
min_limit
1096+
));
1097+
1098+
assert_asset_state!(
1099+
100,
1100+
AssetReserveState {
1101+
reserve: 2000 * ONE + sell_amount,
1102+
hub_reserve: 1951219512195122,
1103+
shares: 2000000000000000,
1104+
protocol_shares: Balance::zero(),
1105+
cap: DEFAULT_WEIGHT_CAP,
1106+
tradable: Tradability::default(),
1107+
}
1108+
);
1109+
assert_asset_state!(
1110+
200,
1111+
AssetReserveState {
1112+
reserve: 1953776507028830,
1113+
hub_reserve: 2047317073170732,
1114+
shares: 2000 * ONE,
1115+
protocol_shares: Balance::zero(),
1116+
cap: DEFAULT_WEIGHT_CAP,
1117+
tradable: Tradability::default(),
1118+
}
1119+
);
1120+
1121+
assert_eq!(Tokens::free_balance(100, &LP1), 950_000_000_000_000);
1122+
assert_eq!(Tokens::free_balance(200, &LP1), 41601143674053);
1123+
assert_eq!(Tokens::free_balance(200, &TRADE_FEE_COLLECTOR), 4622349297117);
1124+
assert_eq!(Tokens::free_balance(LRNA, &PROTOCOL_FEE_COLLECTOR), 731707317073);
1125+
// Account for 200 asset
1126+
let initial_reserve = 2000 * ONE;
1127+
let omnipool_200_reserve = Tokens::free_balance(200, &Omnipool::protocol_account());
1128+
let fee_collector = Tokens::free_balance(200, &TRADE_FEE_COLLECTOR);
1129+
let buy_amount = Tokens::free_balance(200, &LP1);
1130+
assert_eq!(initial_reserve, omnipool_200_reserve + buy_amount + fee_collector);
1131+
});
1132+
}

pallets/referrals/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-referrals"
3-
version = "1.3.0"
3+
version = "1.3.1"
44
authors = ['GalacticCouncil']
55
edition = "2021"
66
license = "Apache-2.0"

pallets/referrals/src/lib.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub mod traits;
5151

5252
use codec::{Decode, Encode, MaxEncodedLen};
5353
use frame_support::pallet_prelude::{DispatchResult, Get};
54-
use frame_support::traits::fungibles::Mutate;
54+
use frame_support::traits::fungibles::{Inspect, Mutate};
5555
use frame_support::traits::tokens::Preservation;
5656
use frame_support::{defensive, ensure, transactional};
5757
use frame_system::{
@@ -696,13 +696,15 @@ impl<T: Config> Pallet<T> {
696696
.saturating_add(trader_reward)
697697
.saturating_add(external_reward);
698698
ensure!(total_taken <= amount, Error::<T>::IncorrectRewardCalculation);
699+
let balance_before = T::Currency::total_balance(asset_id.clone(), &Self::pot_account_id());
699700
T::Currency::transfer(
700701
asset_id.clone(),
701702
&source,
702703
&Self::pot_account_id(),
703704
total_taken,
704705
Preservation::Preserve,
705706
)?;
707+
let balance_after = T::Currency::total_balance(asset_id.clone(), &Self::pot_account_id());
706708

707709
let referrer_shares = if ref_account.is_some() {
708710
multiply_by_rational_with_rounding(referrer_reward, price.n, price.d, Rounding::Down)
@@ -750,6 +752,13 @@ impl<T: Config> Pallet<T> {
750752
PendingConversions::<T>::insert(asset_id, ());
751753
}
752754

753-
Ok(Some((total_taken, Self::pot_account_id())))
755+
// To support ATokens - we might need to allow tolerance of 1 unit
756+
// we calculated the shares based on calculated total_taken (which is correct)
757+
// but we need to report back that we have actually taken +1 sometimes.
758+
let actual_taken = balance_after.saturating_sub(balance_before);
759+
let actual_diff = actual_taken.abs_diff(total_taken);
760+
ensure!(actual_diff <= 1, ArithmeticError::Overflow);
761+
762+
Ok(Some((actual_taken, Self::pot_account_id())))
754763
}
755764
}

pallets/staking/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-staking"
3-
version = "4.1.6"
3+
version = "4.1.7"
44
authors = ['GalacticCouncil']
55
edition = "2021"
66
license = "Apache-2.0"

pallets/staking/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,8 +983,16 @@ impl<T: Config> Pallet<T> {
983983
amount: Balance,
984984
) -> Result<Option<(Balance, T::AccountId)>, DispatchError> {
985985
if asset == T::NativeAssetId::get() && Self::is_initialized() {
986+
let balance_before = T::Currency::total_balance(asset, &Self::pot_account_id());
986987
T::Currency::transfer(asset, &source, &Self::pot_account_id(), amount)?;
987-
Ok(Some((amount, Self::pot_account_id())))
988+
let balance_after = T::Currency::total_balance(asset, &Self::pot_account_id());
989+
990+
// To support ATokens - we might need to allow tolerance of 1 unit
991+
// and we need to report back that we have actually taken +1 sometimes.
992+
let actual_taken = balance_after.saturating_sub(balance_before);
993+
let actual_diff = actual_taken.abs_diff(amount);
994+
ensure!(actual_diff <= 1, Error::<T>::Arithmetic);
995+
Ok(Some((actual_taken, Self::pot_account_id())))
988996
} else {
989997
Ok(None)
990998
}

0 commit comments

Comments
 (0)