Skip to content

Commit 72c01a9

Browse files
authored
if transfer reward failed, put back the rewards into pool (#2201)
1 parent 950abef commit 72c01a9

3 files changed

Lines changed: 95 additions & 7 deletions

File tree

modules/incentives/src/lib.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ pub mod module {
285285
#[transactional]
286286
pub fn claim_rewards(origin: OriginFor<T>, pool_id: PoolId) -> DispatchResult {
287287
let who = ensure_signed(origin)?;
288+
288289
Self::do_claim_rewards(who, pool_id)
289290
}
290291

@@ -516,15 +517,29 @@ impl<T: Config> Pallet<T> {
516517
let deduction_amount = deduction_rate.saturating_mul_int(pending_reward).min(pending_reward);
517518
if !deduction_amount.is_zero() {
518519
// re-accumulate deduction to rewards pool if deduction amount is not zero
519-
<orml_rewards::Pallet<T>>::accumulate_reward(&pool_id, currency_id, deduction_amount)?;
520+
let _ = <orml_rewards::Pallet<T>>::accumulate_reward(&pool_id, currency_id, deduction_amount).map_err(|e| {
521+
log::error!(
522+
target: "incentives",
523+
"accumulate_reward: failed to accumulate reward to non-existen pool {:?}, reward_currency_id {:?}, reward_amount {:?}: {:?}",
524+
pool_id, currency_id, deduction_amount, e
525+
);
526+
});
520527
}
521528
(pending_reward.saturating_sub(deduction_amount), deduction_amount)
522529
};
523530

524-
// transfer the actual reward(pending reward exclude deduction) to user from the pool. it should not
525-
// affect the process, ignore the result to continue. if it fails, just the user will not
526-
// be rewarded, there will not increase user balance.
527-
T::Currency::transfer(currency_id, &Self::account_id(), &who, actual_amount)?;
531+
// transfer to `who` maybe fail because of the reward amount is below ED and `who` is not alive.
532+
// if transfer failed, do not throw err directly and try to put the tiny reward back to pool.
533+
let res = T::Currency::transfer(currency_id, &Self::account_id(), &who, actual_amount);
534+
if res.is_err() {
535+
let _ = <orml_rewards::Pallet<T>>::accumulate_reward(&pool_id, currency_id, actual_amount).map_err(|e| {
536+
log::error!(
537+
target: "incentives",
538+
"accumulate_reward: failed to accumulate reward to non-existen pool {:?}, reward_currency_id {:?}, reward_amount {:?}: {:?}",
539+
pool_id, currency_id, actual_amount, e
540+
);
541+
});
542+
}
528543

529544
Self::deposit_event(Event::ClaimRewards {
530545
who: who.clone(),

modules/incentives/src/mock.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,12 @@ impl frame_system::Config for Runtime {
8989
}
9090

9191
parameter_type_with_key! {
92-
pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance {
93-
Default::default()
92+
pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance {
93+
94+
match currency_id {
95+
CurrencyId::Token(TokenSymbol::AUSD) => 10,
96+
_ => Default::default()
97+
}
9498
};
9599
}
96100

modules/incentives/src/tests.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,75 @@ fn payout_works() {
512512
});
513513
}
514514

515+
#[test]
516+
fn transfer_failed_when_claim_rewards() {
517+
ExtBuilder::default().build().execute_with(|| {
518+
assert_ok!(TokensModule::deposit(AUSD, &VAULT::get(), 100));
519+
RewardsModule::add_share(&ALICE::get(), &PoolId::Loans(BTC), 100);
520+
RewardsModule::add_share(&BOB::get(), &PoolId::Loans(BTC), 100);
521+
assert_ok!(RewardsModule::accumulate_reward(&PoolId::Loans(BTC), AUSD, 18));
522+
523+
assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 100);
524+
assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 0);
525+
assert_eq!(
526+
RewardsModule::pool_infos(PoolId::Loans(BTC)),
527+
PoolInfo {
528+
total_shares: 200,
529+
rewards: vec![(AUSD, (18, 0))].into_iter().collect(),
530+
}
531+
);
532+
assert_eq!(
533+
RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()),
534+
(100, Default::default())
535+
);
536+
537+
// Alice claim rewards, but the rewards are put back to pool because transfer rewards failed.
538+
assert_ok!(IncentivesModule::claim_rewards(
539+
Origin::signed(ALICE::get()),
540+
PoolId::Loans(BTC)
541+
));
542+
543+
assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 100);
544+
assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 0);
545+
assert_eq!(
546+
RewardsModule::pool_infos(PoolId::Loans(BTC)),
547+
PoolInfo {
548+
total_shares: 200,
549+
rewards: vec![(AUSD, (27, 9))].into_iter().collect(),
550+
}
551+
);
552+
assert_eq!(
553+
RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()),
554+
(100, vec![(AUSD, 9)].into_iter().collect())
555+
);
556+
557+
assert_eq!(TokensModule::free_balance(AUSD, &BOB::get()), 0);
558+
assert_eq!(
559+
RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()),
560+
(100, Default::default())
561+
);
562+
563+
// BOB claim reward and receive the reward.
564+
assert_ok!(IncentivesModule::claim_rewards(
565+
Origin::signed(BOB::get()),
566+
PoolId::Loans(BTC)
567+
));
568+
assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 87);
569+
assert_eq!(TokensModule::free_balance(AUSD, &BOB::get()), 13);
570+
assert_eq!(
571+
RewardsModule::pool_infos(PoolId::Loans(BTC)),
572+
PoolInfo {
573+
total_shares: 200,
574+
rewards: vec![(AUSD, (27, 22))].into_iter().collect(),
575+
}
576+
);
577+
assert_eq!(
578+
RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()),
579+
(100, vec![(AUSD, 13)].into_iter().collect())
580+
);
581+
});
582+
}
583+
515584
#[test]
516585
fn claim_rewards_works() {
517586
ExtBuilder::default().build().execute_with(|| {

0 commit comments

Comments
 (0)