def test_get_fees_unreasonable_fee(): with mock.patch('two1.wallet.fees.requests.get') as mock_request: return_value = mock_request.return_value return_value.status_code = 200 fee_per_byte = fees.DEFAULT_FEE_PER_KB / 1000 return_value.json = lambda: { 'halfHourFee': fee_per_byte * 10, } with TestCase().assertRaises(exceptions.UnreasonableFeeError): fees.get_fees()
def test_get_fees_cointape_server_down(): # Mock a response that doesn't have the correct data with mock.patch('two1.wallet.fees.requests.get') as mock_request: mock_request.return_value.status_code = 400 f = fees.get_fees() assert f['per_kb'] == fees.DEFAULT_FEE_PER_KB
def utxo_selector_smallest_first(utxos_by_addr, amount, num_outputs, fees=None): f = get_fees() input_fee = f['per_input'] output_fee = f['per_output'] # Order the utxos by amount utxo_tuple_list = _get_utxos_addr_tuple_list(utxos_by_addr) ordered_utxos = sorted(utxo_tuple_list, key=lambda utxo_addr_tuple: utxo_addr_tuple[1].value) calc_fees = num_outputs * output_fee utxos_to_use = {} utxo_sum = 0 for addr, utxo in ordered_utxos: tf = fees if fees is not None else calc_fees if utxo_sum < amount + tf: utxo_sum += utxo.value if addr in utxos_to_use: utxos_to_use[addr].append(utxo) else: utxos_to_use[addr] = [utxo] calc_fees += input_fee else: break fee = fees if fees is not None else calc_fees rv = utxos_to_use, fee if utxo_sum < amount + fee: rv = {}, fee return rv
def test_get_fees(): f = fees.get_fees() assert 'per_kb' in f assert 'per_input' in f assert 'per_output' in f assert f['per_kb'] >= 0 and f['per_kb'] <= 100000 # Mock a response that doesn't have the correct data fees._fee_session.request = MagicMock( return_value=type('obj', (object,), {'status_code': 400, "json": lambda: "Not Json", 'text': "Error"})) f = fees.get_fees() assert f['per_kb'] == fees.DEFAULT_FEE_PER_KB
def test_get_fees(): f = fees.get_fees() assert 'per_kb' in f assert 'per_input' in f assert 'per_output' in f assert f['per_kb'] >= 0 and f['per_kb'] <= 100000 # Mock a response that doesn't have the correct data fees._fee_session.request = MagicMock( return_value=type('obj', (object, ), { 'status_code': 400, "json": lambda: "Not Json", 'text': "Error" })) f = fees.get_fees() assert f['per_kb'] == fees.DEFAULT_FEE_PER_KB
def sweep(ctx): """ Sweep your machine wallet to your primary wallet. \b Sweep your machine wallet to your primary wallet. $ 21 sell sweep """ manager = ctx.obj['manager'] logger.info(click.style("Sweeping all service balances.", fg=cli_helpers.TITLE_COLOR)) provider = TwentyOneProvider() try: wallet = Two1Wallet.import_from_mnemonic(provider, manager.get_services_mnemonic()) except Exception: logger.info(click.style("Error: unable to import wallet mnemonic. Please check to make " "sure the mnemonic exists in %s " "or contact [email protected]." % Two1Composer.COMPOSE_FILE, fg="magenta")) utxos = wallet.get_utxos(include_unconfirmed=True, accounts=wallet._accounts) utxo_sum = wallet._sum_utxos(utxos) fee_amounts = txn_fees.get_fees() total_value, num_utxos = utxo_sum def fee_calc_small(num_utxos, total_value, fee_amounts): maybe_fee = _fee_calc(num_utxos, total_value, fee_amounts) return int(min([total_value / 2, maybe_fee])) fee = fee_calc_small(num_utxos, total_value, fee_amounts) if click.confirm(click.style("Sweeping %s satoshis to your primary wallet. This will incur a " "fee of approximately %d satoshis.\n" "Would you like to continue?" % (total_value, fee), fg=cli_helpers.PROMPT_COLOR)): master = Two1Wallet(manager.composer.wallet_file, provider) try: wallet.sweep(master.current_address, fee_calculator=fee_calc_small) except WalletBalanceError: cli_helpers.print_str("Sweep", ["Wallet balance (%d satoshis) is less than the dust " "limit. Not Sweeping." % total_value], "FAILED", False) except DustLimitError: cli_helpers.print_str("Sweep", ["Wallet balance (%d satoshis) would be below the " "dust limit when fees are deducted. " "Aborting sweep." % total_value], "FAILED", False) else: cli_helpers.print_str("Sweep", ["Swept %d satoshis, excluding %d satoshis of " "fees" % (total_value - fee, fee)], "SUCCESS", True) else: sys.exit()
def utxo_selector_smallest_first(utxos_by_addr, amount, num_outputs, fees=None): # Order the utxos by amount utxo_tuple_list = _get_utxos_addr_tuple_list(utxos_by_addr) ordered_utxos = sorted( utxo_tuple_list, key=lambda utxo_addr_tuple: utxo_addr_tuple[1].value) if fees is None: f = get_fees() input_fee = f['per_input'] output_fee = f['per_output'] calc_fees = num_outputs * output_fee utxos_to_use = {} utxo_sum = 0 for addr, utxo in ordered_utxos: tf = fees if fees is not None else calc_fees if utxo_sum < amount + tf: utxo_sum += utxo.value if addr in utxos_to_use: utxos_to_use[addr].append(utxo) else: utxos_to_use[addr] = [utxo] if fees is None: calc_fees += input_fee else: break fee = fees if fees is not None else calc_fees rv = utxos_to_use, fee if utxo_sum < amount + fee: rv = {}, fee return rv
def sweep(ctx, services, all, channels): """ Sweep service wallets to primary wallet. \b Sweep all service wallets to primary wallet. $ 21 sell sweep --all \b Sweep the wallets of services to primary wallet. $ 21 sell sweep <services>... """ services_present = len(services) > 0 all_present = all is True channels_present = channels is True if services_present + all_present + channels_present != 1: logger.info(ctx.command.get_help(ctx)) sys.exit() manager = ctx.obj['manager'] provider = TwentyOneProvider() master = Two1Wallet(manager.composer.PRIMARY_WALLET_FILE, provider) if not channels_present: try: with open(manager.composer.SERVICES_WALLET_FILE, "r") as f: services_info = json.load(f) except: logger.info(click.style("The services wallet information file seems to be corrupted, exiting..."), fg="magenta") sys.exit() requested_services_set = frozenset(services) available_services_set = frozenset(services_info.keys()) if all: start_string = "Sweeping all service balances..." clients = {service_name: Two1Wallet.import_from_mnemonic(provider, service_details['mnemonic']) for service_name, service_details in services_info.items()} elif requested_services_set.issubset(available_services_set): start_string = "Sweeping balances for " + ", ".join(services) + "..." clients = {service_name: Two1Wallet.import_from_mnemonic(provider, services_info[service_name]['mnemonic']) for service_name in services} else: unavailable_requested_services = requested_services_set.difference(available_services_set) if len(unavailable_requested_services) > 1: logger.info(click.style("Services {} aren't available to be sweeped".format(", ".join(unavailable_requested_services)), fg="magenta")) else: logger.info(click.style("Service {} isn't available to be sweeped".format(", ".join(unavailable_requested_services)), fg="magenta")) sys.exit() logger.info(click.style(start_string, fg=cli_helpers.TITLE_COLOR)) else: logger.info(click.style("Sweeping payment server balances...", fg=cli_helpers.TITLE_COLOR)) try: with open(manager.composer.PAYMENTS_WALLET_FILE, "r") as f: payments_info = json.load(f) except: logger.info(click.style("The payment server wallet information file seems to be corrupted, exiting..."), fg="magenta") sys.exit() clients = {"payment channels": Two1Wallet.import_from_mnemonic(provider, payments_info['mnemonic'])} logger.info(click.style(start_string, fg=cli_helpers.TITLE_COLOR)) utxo_sums = {} for service_name, wallet in clients.items(): utxos_by_addr = wallet.get_utxos(include_unconfirmed=True, accounts=wallet._accounts) utxo_sums[service_name] = wallet._sum_utxos(utxos_by_addr) fee_dict = {} fee_amounts = txn_fees.get_fees() for service_name, utxo_sum in utxo_sums.items(): total_value, num_utxos = utxo_sum fee_dict[service_name] = fee_calc_small(num_utxos, total_value, fee_amounts) fees = sum(fee_dict.values()) if click.confirm(click.style("This will incur a fee of approximately %d satoshis in total. " "Would you like to continue?" % fees, fg=cli_helpers.PROMPT_COLOR)): for service_name, wallet in clients.items(): try: wallet.sweep(master.current_address, fee_calculator=fee_calc_small) except WalletBalanceError: cli_helpers.print_str(service_name, ["Wallet balance (%d satoshis) is less than the dust limit. Not Sweeping." % utxo_sums[service_name][0]], "FALSE", False) except DustLimitError: cli_helpers.print_str(service_name, ["Wallet balance (%d satoshis) would be below the dust limit when fees are deducted. Not Sweeping." % utxo_sums[service_name][0]], "FALSE", False) else: total_value = utxo_sums[service_name][0] fees_incurred = fee_dict[service_name] cli_helpers.print_str(service_name, ["Sweeped %d satoshis, excluding %d satoshis of fees" % (total_value - fees_incurred, fees_incurred)], "TRUE", True) else: sys.exit()