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.ratio = ratio rl0.ratio3 = ratio rewards.append(rl0) rewards[0].type = TYPE_OWNERS_PARENT rewards[1].type = TYPE_FOUNDERS_PARENT rewards.append( RewardLog("addrdummy", "D", 0, 0).skip("skipped for testing", 3)) founders_map = {"addr1": 0.4, "addr2": 0.6} owners_map = {"addr1": 0.6, "addr2": 0.4} phase4 = CalculatePhase4(founders_map, owners_map) new_rewards, new_total_reward = phase4.calculate(rewards, total_reward) # new_total_reward = total_reward self.assertEqual(total_reward, new_total_reward) # check new ratios sum up to 1 # old and new reward amount is the same ratio_sum = 0.0 # filter out skipped records new_rewards = list(rl for rl in new_rewards if not rl.skipped) # 2 owner, 2 founders and 3 delegators self.assertEqual(7, len(new_rewards)) founder_ratio = 0.0 owner_ratio = 0.0 for rl4 in new_rewards: if rl4.skipped: continue if rl4.type == TYPE_FOUNDER: founder_ratio += rl4.ratio4 if rl4.type == TYPE_OWNER: owner_ratio += rl4.ratio4 ratio_sum += rl4.ratio4 self.assertAlmostEqual(1.0, ratio_sum, delta=1e-6) self.assertAlmostEqual(0.25, owner_ratio, delta=1e-6) self.assertAlmostEqual(0.05, founder_ratio, delta=1e-6)
def calculate(self, reward_provider_model): phase0 = CalculatePhase0(reward_provider_model) rwrd_logs = phase0.calculate() total_rwrd_amnt = reward_provider_model.computed_reward_amount logger.info("Total rewards before processing is {:,} mutez.".format( total_rwrd_amnt)) if total_rwrd_amnt == 0: logger.debug("NO REWARDS to process!") return [], 0 assert reward_provider_model.delegate_staking_balance == sum( [rl.staking_balance for rl in rwrd_logs]) assert self.almost_equal(1, sum([rl.ratio for rl in rwrd_logs])) # calculate phase 1 phase1 = CalculatePhase1(self.rules_model.exclusion_set1, self.min_delegation_amnt) rwrd_logs, total_rwrd_amnt = phase1.calculate(rwrd_logs, total_rwrd_amnt) assert self.almost_equal( 1, sum([rl.ratio for rl in rwrd_logs if not rl.skipped])) # calculate phase 2 phase2 = CalculatePhase2(self.rules_model.exclusion_set2, self.min_delegation_amnt) rwrd_logs, total_rwrd_amnt = phase2.calculate(rwrd_logs, total_rwrd_amnt) assert self.almost_equal( 1, sum([rl.ratio for rl in rwrd_logs if not rl.skipped])) # calculate phase 3 phase3 = CalculatePhase3(self.fee_calc, self.rules_model.exclusion_set3, self.min_delegation_amnt) rwrd_logs, total_rwrd_amnt = phase3.calculate(rwrd_logs, total_rwrd_amnt) assert self.almost_equal( 1, sum([rl.ratio for rl in rwrd_logs if not rl.skipped])) founder_parent = next( filter(lambda x: x.type == TYPE_FOUNDERS_PARENT, rwrd_logs), None) calculated_founder_rewards = sum([ rl.ratio2 for rl in rwrd_logs if rl.skippedatphase == 3 ]) + sum([rl.service_fee_ratio for rl in rwrd_logs if not rl.skipped]) if founder_parent: assert self.almost_equal(founder_parent.ratio3, calculated_founder_rewards) else: assert self.almost_equal(0, calculated_founder_rewards) owners_parent = next( filter(lambda x: x.type == TYPE_OWNERS_PARENT, rwrd_logs), None) if owners_parent: assert owners_parent.service_fee_rate == 0 phase4 = CalculatePhase4(self.founders_map, self.owners_map) rwrd_logs, total_rwrd_amnt = phase4.calculate(rwrd_logs, total_rwrd_amnt) # calculate amounts phase_last = CalculatePhaseFinal() rwrd_logs, total_rwrd_amnt = phase_last.calculate( rwrd_logs, total_rwrd_amnt) # sort rewards according to type and balance rwrd_logs.sort(key=functools.cmp_to_key(cmp_by_type_balance)) # check if there is difference between sum of calculated amounts and total_rewards total_amount_to_pay = sum( [rl.amount for rl in rwrd_logs if not rl.skipped]) amnt_pay_diff = abs(total_rwrd_amnt - total_amount_to_pay) logger.info("Total rewards after processing is {:,} mutez.".format( total_rwrd_amnt)) logger.info( "Total amount to pay is {:,} mutez".format(total_amount_to_pay)) logger.info( "Difference between total rewards and total payment amount is {:,} mutez. " "This is due to floating point arithmetic. (max allowed diff is {:,})" .format(amnt_pay_diff, MINOR_DIFF)) return rwrd_logs, total_rwrd_amnt