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)
def test_attempt_single_batch_tz(sign, request_url, request_url_post): network_config = {"BLOCK_TIME_IN_SEC": 60, "MINIMAL_BLOCK_DELAY": 30} batch_payer = BatchPayer( node_url="node_addr", pymnt_addr=TEST_TZ_ADDRESS, clnt_mngr=ClientManager( node_endpoint=PUBLIC_NODE_URL[CURRENT_TESTNET], signer_endpoint=PRIVATE_SIGNER_URL, ), delegator_pays_ra_fee=True, delegator_pays_xfer_fee=True, network_config=network_config, plugins_manager=MagicMock(), dry_run=False, ) batch_payer.base_counter = 0 reward_log = RewardLog( address=TEST_TZ_ADDRESS, type="D", staking_balance=80, current_balance=100, ) reward_log.adjusted_amount = 15577803 reward_log.skipped = False opt_counter = OpCounter() status, operation_hash, _ = batch_payer.attempt_single_batch([reward_log], opt_counter, dry_run=True) assert status == PaymentStatus.DONE assert operation_hash is None assert reward_log.delegator_transaction_fee == TZTX_FEE assert opt_counter.counter == 3209358
def test_simulate_single_operation(): default_fee = TZTX_FEE network_config = {"BLOCK_TIME_IN_SEC": 60, "MINIMAL_BLOCK_DELAY": 30} batch_payer = BatchPayer( node_url="node_addr", pymnt_addr="tz1234567890123456789012345678901234", clnt_mngr=ClientManager( node_endpoint=PUBLIC_NODE_URL[CURRENT_TESTNET], signer_endpoint=PRIVATE_SIGNER_URL, ), delegator_pays_ra_fee=True, delegator_pays_xfer_fee=True, network_config=network_config, plugins_manager=MagicMock(), dry_run=False, ) batch_payer.base_counter = 0 reward_log = RewardLog( address="KT1P3Y1mkGASzuJqLh7uGuQEvHatztGuQRgC", type="D", staking_balance=0, current_balance=0, ) reward_log.amount = 15577803 reward_log.skipped = False simulation_status, simulation_results = batch_payer.simulate_single_operation( reward_log, reward_log.amount, "hash", "unittest") assert PaymentStatus.DONE == simulation_status consumed_gas, tx_fee, storage = simulation_results assert 150 == consumed_gas assert 410 == default_fee + consumed_gas * MUTEZ_PER_GAS_UNIT assert int == type(storage) # type of storage should be int assert 24 == storage
def test_calculate(self): rewards = [] ratios = { "addr1": 0.25, "addr2": 0.05, "addr3": 0.3, "addr4": 0.15, "addr5": 0.25, } total_reward = 1000 for i, addr in enumerate(ratios, start=1): rl0 = RewardLog( address="addr" + str(i), type="D", staking_balance=total_reward * ratios[addr], current_balance=0, ) rl0.ratio1 = ratios[addr] rewards.append(rl0) rewards.append(RewardLog("addrdummy", "D", 0, 0).skip("skipped for testing", 2)) excluded_set = {"addr1"} phase2 = CalculatePhase2(excluded_set) new_rewards, new_total_reward = phase2.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 for pr_new in new_rewards: if pr_new.skipped: continue ratio1 = ratios[pr_new.address] # actual and returning ratio1 self.assertEqual(ratio1, pr_new.ratio1) # difference between new amount and old amount is # C+C*(a/1-a)-C = C*(a/1-a) # --> # C'*Total = C *Total + C*(a/1-a)*Total self.assertAlmostEqual( ratio1 * total_reward, pr_new.ratio2 * new_total_reward - ratio1 * (0.25 / 0.75) * new_total_reward, delta=0.000001, ) ratio_sum = 0.0 for pr_new in new_rewards: if pr_new.ratio2 is None: continue ratio_sum += pr_new.ratio2 self.assertEqual(1.0, ratio_sum)
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 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_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, )
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", balance=total_reward * ratio) rl0.ratio4 = ratio rewards.append(rl0) rewards[0].address = "addr1" rewards[1].address = "addr1" rewards.append( RewardLog("addrdummy", "D", 0).skip("skipped for testing", 4)) phase5 = CalculatePhase5() new_rewards, new_total_reward = phase5.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 = sum(rl.ratio5 for rl in new_rewards) # 2 records are merged self.assertEqual(4, len(new_rewards)) self.assertAlmostEqual(1.0, ratio_sum, delta=1e-6) # ratio of merged record must be 0.30 (0.25+0.05) self.assertAlmostEqual(0.30, list( filter( lambda rl: rl.type == TYPE_MERGED, filter(lambda rl: not rl.skipped, new_rewards)))[0].ratio5, delta=1e-6)
def from_payment_csv_dict_row(row, cycle): reward_log = RewardLog(row["address"], row["type"], 0, 0) reward_log.cycle = cycle reward_log.adjusted_amount = int(row["amount"]) reward_log.hash = None if row["hash"] == "None" else row["hash"] reward_log.paid = PaymentStatus[str(row["paid"]).upper()] reward_log.desc = str(row["description"]) return reward_log
def FromPaymentCSVDictRow(self, row, cyle): rl = RewardLog(row["address"], row["type"], None) rl.cycle = cyle rl.amount = int(row["amount"]) rl.hash = None if row["hash"] == 'None' else row["hash"] rl.balance = 0 if rl.balance == None else rl.balance rl.paid = PaymentStatus(int(row["paid"])) # rl.child = None if row["child"] == 'None' else row["child"] return rl
def from_payment_csv_dict_row(row, cycle): rl = RewardLog(row["address"], row["type"], 0, 0) rl.cycle = cycle rl.amount = int(row["amount"]) rl.hash = None if row["hash"] == "None" else row["hash"] rl.paid = PaymentStatus(int(row["paid"])) return rl
def FromPaymentCSVDictRow(self, row, cycle): rl = RewardLog(row["address"], row["type"], 0, 0) rl.cycle = cycle rl.amount = int(row["amount"]) rl.hash = None if row["hash"] == 'None' else row["hash"] rl.paid = PaymentStatus(int(row["paid"])) return rl
def test_simulate_single_operation(): config = configparser.ConfigParser() assert os.path.isfile(FEE_INI) is True config.read(FEE_INI) default_fee = int(config["KTTX"]["fee"]) network_config = {"BLOCK_TIME_IN_SEC": 64} batch_payer = BatchPayer( node_url="node_addr", pymnt_addr="tz1234567890123456789012345678901234", clnt_mngr=ClientManager( node_endpoint="https://testnet-tezos.giganode.io:443", signer_endpoint="http://127.0.0.1:6732", ), delegator_pays_ra_fee=True, delegator_pays_xfer_fee=True, network_config=network_config, plugins_manager=MagicMock(), dry_run=False, ) batch_payer.base_counter = 0 reward_log = RewardLog( address="KT1P3Y1mkGASzuJqLh7uGuQEvHatztGuQRgC", type="D", staking_balance=0, current_balance=0, ) reward_log.amount = 15577803 reward_log.skipped = False simulation_status, simulation_results = batch_payer.simulate_single_operation( reward_log, reward_log.amount, "hash", "unittest") assert PaymentStatus.DONE == simulation_status consumed_gas, tx_fee, storage = simulation_results assert 150 == consumed_gas assert 589 == default_fee + consumed_gas * MUTEZ_PER_GAS_UNIT assert int == type(storage) # type of storage should be int assert 24 == storage
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)
def main(args): logger.info( "Arguments Configuration = {}".format(json.dumps(args.__dict__, indent=1)) ) # Load payments file payments_file = os.path.expanduser(os.path.normpath(args.payments_file)) if not os.path.isfile(payments_file): raise Exception("payments_file ({}) does not exist.".format(payments_file)) with open(payments_file, "r") as file: payment_lines = file.readlines() payments_dict = {} for line in payment_lines: pkh, amt = line.split(":") pkh = pkh.strip() amt = float(amt.strip()) payments_dict[pkh] = amt if not payments_dict: raise Exception("No payments to process") # Check if dry-run dry_run = args.dry_run # Get reporting directories reports_dir = os.path.expanduser(os.path.normpath(args.base_directory)) # Check the disk size at the reports dir location if disk_is_full(reports_dir): raise Exception( "Disk is full at {}. Please free space to continue saving reports.".format( reports_dir ) ) # if in reports run mode, do not create consumers # create reports in reports directory if dry_run: reports_dir = os.path.join(reports_dir, SIMULATIONS_DIR, "") else: reports_dir = os.path.join(reports_dir, REPORTS_DIR, "") reports_dir = os.path.join(reports_dir, "manual", "") payments_root = get_payment_root(reports_dir, create=True) get_successful_payments_dir(payments_root, create=True) get_failed_payments_dir(payments_root, create=True) client_manager = ClientManager( node_endpoint=args.node_endpoint, signer_endpoint=args.signer_endpoint ) for i in range(NB_CONSUMERS): c = PaymentConsumer( name="manual_payment_consumer", payments_dir=payments_root, key_name=args.paymentaddress, payments_queue=payments_queue, node_addr=args.node_endpoint, client_manager=client_manager, dry_run=dry_run, reactivate_zeroed=False, delegator_pays_ra_fee=False, delegator_pays_xfer_fee=False, ) time.sleep(1) c.start() base_name_no_ext = os.path.basename(payments_file) base_name_no_ext = os.path.splitext(base_name_no_ext)[0] now = datetime.now() now_str = now.strftime("%Y%m%d%H%M%S") file_name = base_name_no_ext + "_" + now_str payment_items = [] for key, value in payments_dict.items(): pi = RewardLog.ExternalInstance(file_name, key, value) pi.payment = pi.payment * MUTEZ payment_items.append(pi) logger.info( "Reward created for cycle %s address %s amount %f fee %f tz type %s", pi.cycle, pi.address, pi.payment, pi.fee, pi.type, ) payments_queue.put(PaymentBatch(None, 0, payment_items)) payments_queue.put(PaymentBatch(None, 0, [RewardLog.ExitInstance()]))
def main(args): logger.info("Arguments Configuration = {}".format( json.dumps(args.__dict__, indent=1))) # 1- find where configuration is config_dir = os.path.expanduser(args.config_dir) # create configuration directory if it is not present # so that user can easily put his configuration there if config_dir and not os.path.exists(config_dir): os.makedirs(config_dir) # 3- load payments file payments_file = os.path.expanduser(args.payments_file) if not os.path.isfile(payments_file): raise Exception( "payments_file ({}) does not exist.".format(payments_file)) with open(payments_file, 'r') as file: payment_lines = file.readlines() payments_dict = {} for line in payment_lines: pkh, amt = line.split(":") pkh = pkh.strip() amt = float(amt.strip()) payments_dict[pkh] = amt if not payments_dict: raise Exception("No payments to process") # 6- is it a reports run dry_run = args.dry_run # 7- get reporting directories reports_dir = os.path.expanduser(args.reports_dir) # if in reports run mode, do not create consumers # create reports in reports directory if dry_run: reports_dir = os.path.expanduser("./reports") reports_dir = os.path.join(reports_dir, "manual") payments_root = get_payment_root(reports_dir, create=True) get_successful_payments_dir(payments_root, create=True) get_failed_payments_dir(payments_root, create=True) client_manager = ClientManager(node_endpoint=args.node_endpoint, signer_endpoint=args.signer_endpoint) for i in range(NB_CONSUMERS): c = PaymentConsumer(name='manual_payment_consumer', payments_dir=payments_root, key_name=args.paymentaddress, payments_queue=payments_queue, node_addr=args.node_endpoint, client_manager=client_manager, dry_run=dry_run, reactivate_zeroed=False, delegator_pays_ra_fee=False, delegator_pays_xfer_fee=False) time.sleep(1) c.start() base_name_no_ext = os.path.basename(payments_file) base_name_no_ext = os.path.splitext(base_name_no_ext)[0] now = datetime.now() now_str = now.strftime("%Y%m%d%H%M%S") file_name = base_name_no_ext + "_" + now_str payment_items = [] for key, value in payments_dict.items(): pi = RewardLog.ExternalInstance(file_name, key, value) pi.payment = pi.payment * MUTEZ payment_items.append(pi) logger.info( "Reward created for cycle %s address %s amount %f fee %f tz type %s", pi.cycle, pi.address, pi.payment, pi.fee, pi.type) payments_queue.put(PaymentBatch(None, 0, payment_items)) payments_queue.put(PaymentBatch(None, 0, [RewardLog.ExitInstance()]))
def create_exit_payment(): return RewardLog.ExitInstance()
def test_merge(self): rewards = [] # # Alice is a delegate, owner and founder rlAD = RewardLog(address="tz1Alice01", type="D", staking_balance=10000, current_balance=20000) rlAD.amount = 1234 rewards.append(rlAD) rlAO = RewardLog(address="tz1Alice01", type="O", staking_balance=10000, current_balance=0) rlAO.amount = 2345 rewards.append(rlAO) rlAF = RewardLog(address="tz1Alice01", type="F", staking_balance=10000, current_balance=0) rlAF.amount = 3456 rewards.append(rlAF) # # Bob is only a delegate rlBD = RewardLog(address="tz1Bob01", type="D", staking_balance=10000, current_balance=0) rlBD.amount = 5000 rewards.append(rlBD) # # Charlie is an Owner and Founder, not a delegate rlCO = RewardLog(address="tz1Charlie01", type="O", staking_balance=10000, current_balance=0) rlCO.amount = 1122 rewards.append(rlCO) rlCF = RewardLog(address="tz1Charlie01", type="F", staking_balance=10000, current_balance=0) rlCF.amount = 2233 rewards.append(rlCF) # # Merge Alice and Charlie's payouts mergedRewards = CalculatePhaseMerge().calculate(rewards) # Check that there now exists only 3 records. Alice's 3 should be merged to 1, # and Charlie's 2 merged to 1, Bob only had 1 to begin with self.assertEqual(3, len(mergedRewards)) # Check that Alice's merged record equals the original 3 aliceSum = 7035 bobSum = 5000 charlieSum = 3355 for r in mergedRewards: if r.address == "tz1Alice01": self.assertEqual(r.amount, aliceSum) self.assertEqual(r.type, TYPE_MERGED) elif r.address == "tz1Bob01": self.assertEqual(r.amount, bobSum) self.assertEqual(r.type, TYPE_DELEGATOR) elif r.address == "tz1Charlie01": self.assertEqual(r.amount, charlieSum) self.assertEqual(r.type, TYPE_MERGED)
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
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)
def main(args): logger.info("Arguments Configuration = {}".format(json.dumps(args.__dict__, indent=1))) # 1- find where configuration is config_dir = os.path.expanduser(args.config_dir) # create configuration directory if it is not present # so that user can easily put his configuration there if config_dir and not os.path.exists(config_dir): os.makedirs(config_dir) # 2- Load master configuration file if it is present master_config_file_path = os.path.join(config_dir, "master.yaml") master_cfg = {} if os.path.isfile(master_config_file_path): logger.info("Loading master configuration file {}".format(master_config_file_path)) master_parser = YamlConfParser(ConfigParser.load_file(master_config_file_path)) master_cfg = master_parser.parse() else: logger.info("master configuration file not present.") managers = None contracts_by_alias = None addresses_by_pkh = None if 'managers' in master_cfg: managers = master_cfg['managers'] if 'contracts_by_alias' in master_cfg: contracts_by_alias = master_cfg['contracts_by_alias'] if 'addresses_by_pkh' in master_cfg: addresses_by_pkh = master_cfg['addresses_by_pkh'] # 3- load payments file payments_file = os.path.expanduser(args.payments_file) if not os.path.isfile(payments_file): raise Exception("payments_file ({}) does not exist.".format(payments_file)) with open(payments_file, 'r') as file: payment_lines = file.readlines() payments_dict = {} for line in payment_lines: pkh, amt = line.split(":") pkh = pkh.strip() amt = float(amt.strip()) payments_dict[pkh] = amt if not payments_dict: raise Exception("No payments to process") # 3- get client path client_path = get_client_path([x.strip() for x in args.executable_dirs.split(',')], args.docker, args.network, args.verbose) logger.debug("Dune client path is {}".format(client_path)) # 4- get client path client_path = get_client_path([x.strip() for x in args.executable_dirs.split(',')], args.docker, args.network, args.verbose) logger.debug("Dune client path is {}".format(client_path)) # 6- is it a reports run dry_run = args.dry_run # 7- get reporting directories reports_dir = os.path.expanduser(args.reports_dir) # if in reports run mode, do not create consumers # create reports in reports directory if dry_run: reports_dir = os.path.expanduser("./reports") reports_dir = os.path.join(reports_dir, "manual") payments_root = get_payment_root(reports_dir, create=True) get_successful_payments_dir(payments_root, create=True) get_failed_payments_dir(payments_root, create=True) wllt_clnt_mngr = WalletClientManager(client_path, contracts_by_alias, addresses_by_pkh, managers) for i in range(NB_CONSUMERS): c = PaymentConsumer(name='manual_payment_consumer', payments_dir=payments_root, key_name=args.paymentaddress, client_path=client_path, payments_queue=payments_queue, node_addr=args.node_addr, wllt_clnt_mngr=wllt_clnt_mngr, verbose=args.verbose, dry_run=dry_run, delegator_pays_xfer_fee=False) time.sleep(1) c.start() base_name_no_ext = os.path.basename(payments_file) base_name_no_ext = os.path.splitext(base_name_no_ext)[0] now = datetime.now() now_str = now.strftime("%Y%m%d%H%M%S") file_name = base_name_no_ext + "_" + now_str payment_items = [] for key, value in payments_dict.items(): pi = RewardLog.ExternalInstance(file_name, key, value) pi.payment = pi.payment * MUTEZ payment_items.append(pi) logger.info("Reward created for cycle %s address %s amount %f fee %f dn type %s", pi.cycle, pi.address, pi.payment, pi.fee, pi.type) payments_queue.put(PaymentBatch(None, 0, payment_items)) payments_queue.put(PaymentBatch(None, 0, [RewardLog.ExitInstance()]))