示例#1
0
    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.ratio2 = ratio
            rewards.append(rl0)

        rewards.append(
            RewardLog("addrdummy", "D", 0, 0).skip("skipped for testing", 2))

        excluded_set = {"addr1"}

        fee_calculator = ServiceFeeCalculator(set(), dict(), 20)  # 20% fee
        phase3 = CalculatePhase3(fee_calculator, excluded_set)

        new_rewards, new_total_reward = phase3.calculate(rewards, total_reward)

        # filter out skipped records
        new_rewards = list(rl for rl in new_rewards if not rl.skipped)

        # 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
        service_fee_ratio_sum = 0.0

        founder_pl = None
        for rl3 in new_rewards:
            if rl3.skipped:
                continue

            if rl3.type == TYPE_FOUNDERS_PARENT:
                founder_pl = rl3

            ratio_sum += rl3.ratio3
            service_fee_ratio_sum += rl3.service_fee_ratio

        self.assertAlmostEqual(1.0, ratio_sum, delta=ALMOST_ZERO)
        self.assertAlmostEqual(0.15, service_fee_ratio_sum, delta=ALMOST_ZERO)
        self.assertAlmostEqual(0.4, founder_pl.ratio3, delta=ALMOST_ZERO)
    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
示例#3
0
    def test_calculate_sepecials(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",
                            balance=total_reward * ratio)
            rl0.ratio = ratio
            rl0.ratio2 = ratio
            rewards.append(rl0)

        rewards.append(
            RewardLog("addrdummy", "D", 0).skip("skipped for testing", 2))

        excluded_set = {"addr1"}
        supporters_set = {"addr2"}
        specials_map = {"addr3": 30}

        fee_calculator = ServiceFeeCalculator(supporters_set, specials_map,
                                              20)  # 20% fee
        phase3 = CalculatePhase3(fee_calculator, excluded_set)

        new_rewards, new_total_reward = phase3.calculate(rewards, total_reward)

        # filter out skipped records
        new_rewards = list(rl for rl in new_rewards if not rl.skipped)

        # 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
        service_fee_ratio_sum = 0.0

        founder_pl = None
        for rl3 in new_rewards:
            if rl3.skipped:
                continue

            if rl3.type == TYPE_FOUNDERS_PARENT:
                founder_pl = rl3

            ratio_sum += rl3.ratio3
            service_fee_ratio_sum += rl3.service_fee_ratio

        self.assertAlmostEqual(1.0, ratio_sum, delta=1e-6)
        self.assertAlmostEqual(0.17, service_fee_ratio_sum, delta=1e-6)
        self.assertAlmostEqual(0.42, founder_pl.ratio3, delta=1e-6)

        for rl3 in new_rewards:
            if rl3.skipped:
                continue

            if rl3.address == "addr2":
                self.assertEqual(0, rl3.service_fee_rate)
                self.assertEqual(0, rl3.service_fee_ratio)

            if rl3.address == "addr3":
                self.assertEqual(0.3, rl3.service_fee_rate)
                self.assertEqual(specials_map["addr3"] / 100 * rl3.ratio2,
                                 rl3.service_fee_ratio)