def calculate(self, reward_logs=None, total_reward_amount=None): """ :param reward_logs: Nothing is expected. This value is not used. reward_logs are generated from provider object. :param total_reward_amount: Nothing is expected. This value is not used. total amount is calculated in calling function. :return: tuple (reward_logs, total reward amount) reward_logs is a list of RewardLog objects. Last item is owners_parent record. total_reward equals to sum( delegator rewards + owners_parent rewards ) """ ratio_sum = 0.0 total_delegator_balance = 0 reward_logs = [] delegate_staking_balance = self.reward_provider_model.delegate_staking_balance delegators_balance_dict = self.reward_provider_model.delegator_balance_dict # calculate how rewards will be distributed # ratio is stake/total staking balance # total of ratios must be 1 for address, delegator_info in delegators_balance_dict.items(): staking_balance = delegator_info["staking_balance"] current_balance = delegator_info["current_balance"] originaladdress = (delegator_info["originaladdress"] if "originaladdress" in delegator_info else None) total_delegator_balance += staking_balance ratio = staking_balance / delegate_staking_balance reward_item = RewardLog( address=address, type=reward_log.TYPE_DELEGATOR, staking_balance=staking_balance, current_balance=current_balance, originaladdress=originaladdress, ) reward_item.ratio = ratio reward_item.ratio0 = reward_item.ratio ratio_sum += ratio reward_logs.append(reward_item) owners_rl = RewardLog( address=reward_log.TYPE_OWNERS_PARENT, type=reward_log.TYPE_OWNERS_PARENT, staking_balance=delegate_staking_balance - total_delegator_balance, current_balance=0, ) owners_rl.ratio = 1 - ratio_sum owners_rl.ratio0 = owners_rl.ratio reward_logs.append(owners_rl) return reward_logs
def test_calculate(self): rewards = [] ratios = [0.25, 0.05, 0.3, 0.15, 0.25] total_reward = 1000 for i, ratio in enumerate(ratios, start=1): rl0 = RewardLog(address="addr" + str(i), type="D", staking_balance=total_reward * ratio, current_balance=0) rl0.ratio0 = ratio rewards.append(rl0) excluded_set = {"addr1"} phase1 = CalculatePhase1(excluded_set) new_rewards, new_total_reward = phase1.calculate(rewards, total_reward) self.assertEqual(total_reward * (1 - 0.25), new_total_reward) # check new ratios sum up to 1 # old and new reward amount is the same ratio_sum = 0.0 self.assertTrue(new_rewards) # first item is excluded # compare rest of the items for pr_new, ratio0 in zip(new_rewards[1:], ratios[1:]): ratio_sum += pr_new.ratio1 self.assertAlmostEqual(ratio0 * total_reward, pr_new.ratio1 * new_total_reward, delta=0.000001) self.assertEqual(1.0, ratio_sum)