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.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)
コード例 #3
0
    def calculate(self, reward_data3, total_amount):

        new_rewards = []

        # move skipped records to next phase
        for rl3 in self.iterateskipped(reward_data3):
            new_rewards.append(rl3)

        for rl3 in self.filterskipped(reward_data3):
            if rl3.type == TYPE_FOUNDERS_PARENT:
                for addr, ratio in self.founders_map.items():
                    rl4 = RewardLog(addr, TYPE_FOUNDER, 0, 0)
                    # new ratio is parent ratio * ratio of the founder
                    rl4.ratio = ratio * rl3.ratio
                    rl4.ratio4 = rl4.ratio
                    rl4.service_fee_ratio = 0
                    rl4.service_fee_rate = 0
                    rl4.parent = rl3
                    new_rewards.append(rl4)

                # if no founders, add parent object to rewards list
                if not self.founders_map.items():
                    new_rewards.append(rl3)

            elif rl3.type == TYPE_OWNERS_PARENT:
                for addr, ratio in self.owners_map.items():
                    rl4 = RewardLog(addr, TYPE_OWNER,
                                    ratio * rl3.staking_balance, 0)
                    # new ratio is parent ratio * ratio of the owner
                    rl4.ratio = ratio * rl3.ratio
                    rl4.ratio4 = rl4.ratio
                    rl4.service_fee_ratio = 0
                    rl4.service_fee_rate = 0
                    rl4.parent = rl3
                    new_rewards.append(rl4)

                # if no owners, add parent object to rewards list
                if not self.owners_map.items():
                    new_rewards.append(rl3)
            else:
                rl3.ratio4 = rl3.ratio
                new_rewards.append(rl3)

        return new_rewards, total_amount
コード例 #4
0
    def calculate(self, reward_data2, total_amount):

        new_rewards = []
        total_excluded_ratio = 0.0

        for rl2 in self.iterateskipped(reward_data2):
            # move skipped records to next phase
            new_rewards.append(rl2)

        # exclude requested items
        for rl2 in self.filterskipped(reward_data2):
            if rl2.address in self.excluded_set:
                rl2.skip(desc=BY_CONFIGURATION, phase=self.phase)
                new_rewards.append(rl2)
                total_excluded_ratio += rl2.ratio
            elif (
                MIN_DELEGATION_KEY in self.excluded_set
                and rl2.staking_balance < self.min_delegation_amount
            ):
                rl2.skip(desc=BY_MIN_DELEGATION, phase=self.phase)
                new_rewards.append(rl2)
                total_excluded_ratio += rl2.ratio
            else:
                new_rewards.append(rl2)

        total_service_fee_ratio = total_excluded_ratio

        # set fee rates and ratios
        for rl in self.filterskipped(new_rewards):
            rl.service_fee_rate = self.fee_calc.calculate(rl.originaladdress)
            rl.service_fee_ratio = rl.service_fee_rate * rl.ratio
            rl.ratio = rl.ratio - rl.service_fee_ratio
            rl.ratio3 = rl.ratio

            total_service_fee_ratio += rl.service_fee_ratio

        # create founders parent record
        if total_service_fee_ratio > ALMOST_ZERO:
            rl = RewardLog(
                address=TYPE_FOUNDERS_PARENT,
                type=TYPE_FOUNDERS_PARENT,
                staking_balance=0,
                current_balance=0,
            )
            rl.service_fee_rate = 0
            rl.service_fee_ratio = 0
            rl.ratio = total_service_fee_ratio
            rl.ratio3 = rl.ratio

            new_rewards.append(rl)

        return new_rewards, int(total_amount)
コード例 #5
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)
コード例 #6
0
    def calculate(self, reward_logs):
        # if address is in address destination dictionary;
        # then set payment address to mapped address value
        for rl in self.filterskipped(reward_logs):
            rl.ratio6 = rl.ratio

        address_set = set(rl.paymentaddress
                          for rl in self.filterskipped(reward_logs))
        payment_address_list_dict = {addr: [] for addr in address_set}

        # group payments by paymentaddress
        for rl in self.filterskipped(reward_logs):
            payment_address_list_dict[rl.paymentaddress].append(rl)

        reward_data6 = []
        for rl in self.iterateskipped(reward_logs):
            reward_data6.append(rl)

        for addr, rl_list in payment_address_list_dict.items():
            if len(rl_list) > 1:
                total_staking_balance = sum(
                    [rl.staking_balance for rl in rl_list])
                total_current_balance = sum(
                    [rl.current_balance for rl in rl_list])
                total_ratio = sum([rl.ratio for rl in rl_list])
                total_payment_amount = sum([rl.amount for rl in rl_list])
                total_adjusted_payment_amount = sum(
                    [rl.adjusted_amount for rl in rl_list])
                total_adjustment = sum([rl.adjustment for rl in rl_list])
                total_service_fee_amount = sum(
                    [rl.service_fee_amount for rl in rl_list])
                total_service_fee_ratio = sum(
                    [rl.service_fee_ratio for rl in rl_list])

                merged = RewardLog(addr, TYPE_MERGED, total_staking_balance,
                                   total_current_balance)
                merged.ratio = total_ratio
                merged.amount = total_payment_amount
                merged.adjusted_amount = total_adjusted_payment_amount
                merged.adjustment = total_adjustment
                merged.service_fee_amount = total_service_fee_amount
                merged.service_fee_ratio = total_service_fee_ratio
                merged.service_fee_rate = 0
                merged.parents = rl_list

                reward_data6.append(merged)
            else:
                reward_data6.append(rl_list[0])

        return reward_data6
    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.ratio4 = ratio
            rewards.append(rl0)

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

        phaseMapping = CalculatePhaseMapping()
        new_rewards = phaseMapping.calculate(rewards, {"addr2": "addr1"})

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

        # check new ratios sum up to 1
        # old and new reward amount is the same
        ratio_sum = sum(rl.ratio5 for rl in new_rewards)

        # payment address for address2 is address1
        payment_address_set = set(rl.paymentaddress for rl in new_rewards)
        self.assertEqual(4, len(payment_address_set))

        self.assertAlmostEqual(1.0, ratio_sum, delta=ALMOST_ZERO)

        # ratio of records having payment address addr1 must be 0.30 (0.25+0.05)
        self.assertAlmostEqual(
            0.30,
            sum(
                rl.ratio
                for rl in list(
                    filter(
                        lambda rl: rl.paymentaddress == "addr1",
                        filter(lambda rl: not rl.skipped, new_rewards),
                    )
                )
            ),
            delta=ALMOST_ZERO,
        )
コード例 #8
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)