def reclaim_erc20( reclamation_candidates: List[ReclamationCandidate], token_address: TokenAddress, contract_manager: ContractManager, account: Account, web3: Web3, ): reclaim_amount = 0 log.info("Checking chain for claimable tokens", token_address=token_address) for node in reclamation_candidates: client = node.get_client(web3) confirmed_block_hash = client.get_confirmed_blockhash() token = CustomToken(client, token_address, contract_manager, confirmed_block_hash) balance = token.balance_of(to_canonical_address(node.address)) log.debug( "balance", token=to_checksum_address(token_address), balance=balance, address=node.address, ) if balance > 0: drain_amount = balance log.info( "Reclaiming tokens", from_address=node.address, amount=drain_amount.__format__(",d"), ) reclaim_amount += drain_amount assert account.address try: token.transfer(account.address, TokenAmount(drain_amount)) except InsufficientEth: log.warning( "Not sufficient eth in node wallet to reclaim", address=node.address, token_address=token_address, ) continue if reclaim_amount: log.info( "Reclaimed", reclaim_amount=reclaim_amount.__format__(",d"), token_address=to_checksum_address(token.address), )
def test_received_lockedtransfer_closedchannel( raiden_network: List[RaidenService], reveal_timeout, token_addresses, deposit ): app0, app1 = raiden_network registry_address = app0.default_registry.address token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_raiden(app0), app0.default_registry.address, token_address ) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) RaidenAPI(app1).channel_close(registry_address, token_address, app0.address) app0.rpc_client.wait_until_block( target_block_number=BlockNumber(app0.rpc_client.block_number() + 1) ) # Now receive one mediated transfer for the closed channel lock_amount = LockedAmount(10) payment_identifier = PaymentID(1) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=Nonce(1), token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(0), locked_amount=lock_amount, recipient=app1.address, locksroot=make_locksroot(), lock=Lock( amount=PaymentWithFeeAmount(lock_amount), expiration=expiration, secrethash=UNIT_SECRETHASH, ), target=TargetAddress(app1.address), initiator=InitiatorAddress(app0.address), signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[RouteMetadata(route=[app1.address])]), ) sign_and_inject(mediated_transfer_message, app0.signer, app1) # The local state must not change since the channel is already closed assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
def sequential_transfers( server_from: APIServer, server_to: APIServer, number_of_transfers: int, token_address: TokenAddress, identifier_generator: Iterator[int], ) -> None: for _ in range(number_of_transfers): transfer_and_assert( server_from=server_from, server_to=server_to, token_address=token_address, identifier=next(identifier_generator), amount=TokenAmount(1), )
def test_process_payment( pathfinding_service_web3_mock, deposit_to_udc, create_account, get_private_key, make_iou, one_to_n_contract, web3, ): pfs = pathfinding_service_web3_mock service_fee = TokenAmount(1) sender = create_account() privkey = get_private_key(sender) deposit_to_udc(sender, round(1 * UDC_SECURITY_MARGIN_FACTOR_PFS)) web3.testing.mine(pathfinding_service_web3_mock.required_confirmations) one_to_n_address = to_canonical_address(one_to_n_contract.address) # Make payment iou = make_iou(privkey, pfs.address, amount=1) process_payment(iou, pfs, service_fee, one_to_n_address) # The same payment can't be reused with pytest.raises(exceptions.InsufficientServicePayment): process_payment(iou, pfs, service_fee, one_to_n_address) # Increasing the amount would make the payment work again, if we had enough # deposit. But we set the deposit one token too low. deposit_to_udc(sender, round(2 * UDC_SECURITY_MARGIN_FACTOR_PFS) - 1) iou = make_iou(privkey, pfs.address, amount=2) with pytest.raises(exceptions.DepositTooLow): process_payment(iou, pfs, service_fee, one_to_n_address) # With the higher amount and enough deposit, it works again! deposit_to_udc(sender, round(2 * UDC_SECURITY_MARGIN_FACTOR_PFS)) web3.testing.mine(pathfinding_service_web3_mock.required_confirmations) iou = make_iou(privkey, pfs.address, amount=2) process_payment(iou, pfs, service_fee, one_to_n_address) # Make sure the client does not create new sessions unnecessarily iou = make_iou(privkey, pfs.address, expiration_block=20000) with pytest.raises(exceptions.UseThisIOU): process_payment(iou, pfs, service_fee, one_to_n_address) # Complain if the IOU has been claimed iou = make_iou(privkey, pfs.address, amount=3) pfs.database.conn.execute("UPDATE iou SET claimed=1") with pytest.raises(exceptions.IOUAlreadyClaimed): process_payment(iou, pfs, service_fee, one_to_n_address)
def get_initial_amount_for_amount_after_fees( amount_after_fees: PaymentAmount, channels: List[Tuple[NettingChannelState, NettingChannelState]], ) -> Optional[FeesCalculation]: """ Calculates the payment amount including fees to be supplied to the given channel configuration, so that `amount_after_fees` arrives at the target. Note: The channels have to be from the view of the mediator, so for the case A -> B -> C this should be [(B->A, B->C)] """ assert len(channels) >= 1, "Need at least one channel pair" # Backpropagate fees in mediation scenario total = PaymentWithFeeAmount(amount_after_fees) fees: List[FeeAmount] = [] try: for channel_in, channel_out in reversed(channels): assert isinstance(channel_in, NettingChannelState) assert isinstance(channel_out, NettingChannelState) balance_in = get_balance(channel_in.our_state, channel_in.partner_state) balance_out = get_balance(channel_out.our_state, channel_out.partner_state) receivable_amount = TokenAmount(channel_in.our_total_deposit + channel_in.partner_total_deposit - balance_in) before_fees = get_amount_with_fees( amount_without_fees=total, balance_in=balance_in, balance_out=balance_out, schedule_in=channel_in.fee_schedule, schedule_out=channel_out.fee_schedule, receivable_amount=receivable_amount, ) if before_fees is None: return None fee = FeeAmount(before_fees - total) total = PaymentWithFeeAmount(total + fee) fees.append(fee) except UndefinedMediationFee: return None return FeesCalculation(total_amount=PaymentWithFeeAmount(total), mediation_fees=fees)
def test_pfs_rejects_capacity_update_with_impossible_other_capacity( addresses: List[Address], pathfinding_service_mocked_listeners: PathfindingService, ): pathfinding_service_mocked_listeners.chain_id = 1 token_network = TokenNetwork( token_network_address=DEFAULT_TOKEN_NETWORK_ADDRESS, token_address=DEFAULT_TOKEN_ADDRESS, ) pathfinding_service_mocked_listeners.token_networks[ token_network.address] = token_network token_network.handle_channel_opened_event( channel_identifier=ChannelIdentifier(0), participant1=addresses[0], participant2=addresses[1], settle_timeout=15, ) token_network.handle_channel_new_deposit_event( channel_identifier=ChannelIdentifier(0), receiver=addresses[0], total_deposit=100, ) token_network.handle_channel_new_deposit_event( channel_identifier=ChannelIdentifier(0), receiver=addresses[1], total_deposit=100, ) # Check that the new channel has id == 0 assert token_network.channel_id_to_addresses[ChannelIdentifier(0)] == ( addresses[0], addresses[1], ) message = get_updatepfs_message( updating_participant=addresses[0], other_participant=addresses[1], other_capacity=TokenAmount(UINT256_MAX + 1), ) with pytest.raises(InvalidCapacityUpdate) as exinfo: pathfinding_service_mocked_listeners.on_pfs_update(message) assert 'with impossible other_capacity' in str(exinfo.value)
def test_routing_result_order( token_network_model: TokenNetwork, populate_token_network_case_1: None, addresses: List[Address], ): paths = token_network_model.get_paths(addresses[0], addresses[2], value=TokenAmount(10), max_paths=5, hop_bias=1) # 5 paths requested, but only 1 is available assert len(paths) == 1 assert paths[0] == { "path": [addresses[0], addresses[1], addresses[2]], "estimated_fee": 0 }
def f(chain_id=1, **kwargs): balance_proof = make_balance_proof(signer=signer, **kwargs) balance_proof.chain_id = chain_id partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state( balance_proof ) request_monitoring = RequestMonitoring( onchain_balance_proof=partner_signed_balance_proof, reward_amount=TokenAmount(55) ) request_monitoring.sign(non_closing_signer) # usually not a property of RequestMonitoring, but added for convenience in these tests request_monitoring.non_closing_signer = to_checksum_address( # type: ignore non_closing_signer.address ) return request_monitoring
def test_monitor_reward_claimed_event_handler(context: Context, log): context = setup_state_with_closed_channel(context) claim_event = ReceiveMonitoringRewardClaimedEvent( ms_address=context.ms_state.address, amount=TokenAmount(1), reward_identifier="REWARD", block_number=BlockNumber(23), ) monitor_reward_claim_event_handler(claim_event, context) assert log.has("Successfully claimed reward") claim_event.ms_address = Address(bytes([3] * 20)) monitor_reward_claim_event_handler(claim_event, context) assert log.has("Another MS claimed reward")
def test_mfee4(): """ Unit test for the fee calculation in the mfee4_combined_fees scenario """ amount = PaymentAmount(500_000_000_000_000_000) deposit = 1_000_000_000_000_000_000 prop_fee = ppm_fee_per_channel(ProportionalFeeAmount(10_000)) imbalance_penalty = calculate_imbalance_fees( TokenAmount(deposit * 2), ProportionalFeeAmount(20_000) ) fee_schedule = FeeScheduleState( flat=FeeAmount(100 // 2), proportional=prop_fee, imbalance_penalty=imbalance_penalty, cap_fees=False, ) channels = make_channel_pair(fee_schedule, deposit, deposit) # How much do we need to send so that the target receives `amount`? PFS-like calculation. fee_calculation = get_initial_amount_for_amount_after_fees( amount_after_fees=PaymentAmount(amount), channels=[channels, channels] ) assert fee_calculation amount_with_margin = calculate_safe_amount_with_fee( amount, FeeAmount(sum(fee_calculation.mediation_fees)) ) # Calculate mediation fees for both mediators med_fees = [] incoming_amount = amount_with_margin for _ in range(2): outgoing_amount = get_amount_without_fees( amount_with_fees=incoming_amount, channel_in=channels[0], channel_out=channels[1] ) assert outgoing_amount med_fees.append(incoming_amount - outgoing_amount) incoming_amount = outgoing_amount assert amount_with_margin == 543_503_066_141_505_551 # print values for scenario print("{:_} {:_}".format(deposit - amount_with_margin, deposit + amount_with_margin)) for med_fee in running_sum(med_fees): print( "{:_} {:_}".format( deposit - amount_with_margin + med_fee, deposit + amount_with_margin - med_fee ) )
def test_setup_proxies_all_addresses_are_known(): """ Test that startup for proxies works fine if all addresses are given and routing is basic """ chain_id = ChainID(5) config = RaidenConfig(chain_id=chain_id, environment_type=Environment.DEVELOPMENT) config.transport.available_servers = ["http://matrix.example.com"] contracts = load_deployed_contracts_data(config, chain_id) proxy_manager = MockProxyManager(node_address=make_address()) PFS_INFO = PFSInfo( url="my-pfs", price=TokenAmount(12), chain_id=ChainID(5), token_network_registry_address=to_canonical_address( contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]["address"]), user_deposit_address=user_deposit_address_test_default, payment_address=pfs_payment_address_default, confirmed_block_number=BlockNumber(1), message="This is your favorite pathfinding service", operator="John Doe", version="0.0.3", matrix_server="http://matrix.example.com", matrix_room_id="!room-id:matrix.example.com", ) deployed_addresses = load_deployment_addresses_from_contracts(contracts) with patch.object(pathfinding, "get_pfs_info", return_value=PFS_INFO): raiden_bundle = raiden_bundle_from_contracts_deployment( proxy_manager=proxy_manager, token_network_registry_address=deployed_addresses. token_network_registry_address, secret_registry_address=deployed_addresses.secret_registry_address, ) services_bundle = services_bundle_from_contracts_deployment( config=config, proxy_manager=proxy_manager, deployed_addresses=deployed_addresses, routing_mode=RoutingMode.PFS, pathfinding_service_address="my-pfs", enable_monitoring=False, ) assert raiden_bundle assert services_bundle assert raiden_bundle.token_network_registry assert raiden_bundle.secret_registry assert services_bundle.user_deposit assert services_bundle.service_registry
def _deposit_preconditions( self, total_deposit: TokenAmount, beneficiary: Address, token: Token, block_identifier: BlockSpecification, ) -> Tuple[TokenAmount, Dict]: if not isinstance(total_deposit, int): raise ValueError("total_deposit needs to be an integer number.") previous_total_deposit = self.get_total_deposit( address=beneficiary, block_identifier=block_identifier ) amount_to_deposit = TokenAmount(total_deposit - previous_total_deposit) log_details = { "user_deposit_address": pex(self.address), "node": pex(self.node_address), "beneficiary": pex(beneficiary), "new_total_deposit": total_deposit, "previous_total_deposit": previous_total_deposit, } if total_deposit <= previous_total_deposit: msg = ( f"Current total deposit {previous_total_deposit} is already larger " f"than the requested total deposit amount {total_deposit}" ) log.info("deposit failed", reason=msg, **log_details) raise DepositMismatch(msg) current_balance = token.balance_of( address=self.node_address, block_identifier=block_identifier ) if current_balance < amount_to_deposit: msg = ( f"new_total_deposit - previous_total_deposit = {amount_to_deposit} can not " f"be larger than the available balance {current_balance}, " f"for token at address {pex(token.address)}" ) log.info("deposit failed", reason=msg, **log_details) raise DepositMismatch(msg) token.approve(allowed_address=Address(self.address), allowance=amount_to_deposit) return amount_to_deposit, log_details
def test_monitor_reward_claimed_event_handler(context: Context, log): metrics_state = save_metrics_state(metrics.REGISTRY) context = setup_state_with_closed_channel(context) claim_event = ReceiveMonitoringRewardClaimedEvent( ms_address=context.ms_state.address, amount=TokenAmount(1), reward_identifier="REWARD", block_number=BlockNumber(23), ) monitor_reward_claim_event_handler(claim_event, context) assert ( metrics_state.get_delta( "economics_reward_claims_successful_total", labels=metrics.Who.US.to_label_dict() ) == 1.0 ) assert ( metrics_state.get_delta( "economics_reward_claims_token_total", labels=metrics.Who.US.to_label_dict() ) == 1.0 ) assert log.has("Successfully claimed reward") claim_event = dataclasses.replace(claim_event, ms_address=Address(bytes([3] * 20))) monitor_reward_claim_event_handler(claim_event, context) assert ( metrics_state.get_delta( "economics_reward_claims_successful_total", labels=metrics.Who.THEY.to_label_dict() ) == 1.0 ) assert ( metrics_state.get_delta( "economics_reward_claims_token_total", labels=metrics.Who.THEY.to_label_dict() ) == 1.0 ) assert log.has("Another MS claimed reward")
def test_event_filter_for_payments(): secret = factories.make_secret() identifier = PaymentID(1) target = TargetAddress(factories.make_address()) event1 = EventPaymentSentSuccess( token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS, token_network_address=UNIT_TOKEN_NETWORK_ADDRESS, identifier=identifier, amount=PaymentAmount(5), target=target, secret=secret, route=[], ) assert event_filter_for_payments(event=event1, partner_address=None) assert event_filter_for_payments(event=event1, partner_address=Address(target)) assert not event_filter_for_payments( event=event1, partner_address=factories.make_address()) initiator = InitiatorAddress(factories.make_address()) event2 = EventPaymentReceivedSuccess( token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS, token_network_address=UNIT_TOKEN_NETWORK_ADDRESS, identifier=identifier, amount=TokenAmount(5), initiator=initiator, ) assert event_filter_for_payments(event=event2, partner_address=None) assert event_filter_for_payments(event=event2, partner_address=Address(initiator)) assert not event_filter_for_payments( event=event2, partner_address=factories.make_address()) event3 = EventPaymentSentFailed( token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS, token_network_address=UNIT_TOKEN_NETWORK_ADDRESS, identifier=identifier, target=target, reason="whatever", ) assert event_filter_for_payments(event=event3, partner_address=None) assert event_filter_for_payments(event=event3, partner_address=Address(target)) assert not event_filter_for_payments( event=event3, partner_address=factories.make_address())
def deploy_token_and_return_proxy(deploy_client: JSONRPCClient, contract_manager: ContractManager, token_contract_name: str) -> Token: token_contract = deploy_token( deploy_client=deploy_client, contract_manager=contract_manager, initial_amount=TokenAmount(1000 * 10**18), decimals=0, token_name="TKN", token_symbol="TKN", token_contract_name=token_contract_name, ) return Token( jsonrpc_client=deploy_client, token_address=TokenAddress(token_contract.contract_address), contract_manager=contract_manager, )
def total_supply( self, block_identifier: BlockIdentifier = BLOCK_ID_LATEST ) -> Optional[TokenAmount]: """Return the total supply of the token at the given block identifier. Because Token is just an interface, it is not possible to check the bytecode during the proxy instantiation. This means it is possible for the proxy to be instantiated with a a smart contrat address of the wrong type (a non ERC20 contract), or a partial implementation of the ERC20 standard (the function totalSupply is missing). If that happens this method will return `None`. """ total_supply = self.proxy.functions.totalSupply().call(block_identifier=block_identifier) if isinstance(total_supply, int): return TokenAmount(total_supply) return None
def test_routing_mocked_pfs_happy_path_with_updated_iou( happy_path_fixture, one_to_n_address, our_address): addresses, chain_state, channel_states, response, token_network_state = happy_path_fixture _, address2, _, address4 = addresses _, channel_state2 = channel_states iou = make_iou( pfs_config=PFS_CONFIG, our_address=factories.UNIT_TRANSFER_SENDER, one_to_n_address=one_to_n_address, privkey=PRIVKEY, block_number=BlockNumber(10), chain_id=ChainID(5), offered_fee=TokenAmount(1), ) last_iou = copy(iou) with patch.object(requests, "post", return_value=response) as patched: routes, feedback_token = get_best_routes_with_iou_request_mocked( chain_state=chain_state, token_network_state=token_network_state, one_to_n_address=one_to_n_address, from_address=our_address, to_address=address4, amount=50, iou_json_data=dict(last_iou=last_iou.as_json()), ) assert_checksum_address_in_url(patched.call_args[0][0]) assert routes[0].next_hop_address == address2 assert routes[0].forward_channel_id == channel_state2.identifier assert feedback_token == DEFAULT_FEEDBACK_TOKEN # Check for iou arguments in request payload payload = patched.call_args[1]["json"] pfs_config = CONFIG["pfs_config"] old_amount = last_iou.amount assert old_amount < payload["iou"][ "amount"] <= pfs_config.maximum_fee + old_amount assert payload["iou"]["expiration_block"] == last_iou.expiration_block assert payload["iou"]["sender"] == to_checksum_address(last_iou.sender) assert payload["iou"]["receiver"] == to_checksum_address(last_iou.receiver) assert "signature" in payload["iou"]
def update(self, amount, lock): self._pending_locks = channel.compute_locks_with( self._pending_locks, lock) assert self._pending_locks if self.properties: self.properties = factories.replace( self.properties, locked_amount=self.properties.locked_amount + amount, locksroot=compute_locksroot(self._pending_locks), nonce=self.properties.nonce + 1, ) else: self.properties = factories.BalanceProofProperties( transferred_amount=TokenAmount(0), locked_amount=amount, nonce=Nonce(1), locksroot=compute_locksroot(self._pending_locks), canonical_identifier=self._canonical_identifier, )
def test_routing_result_order( token_network_model: TokenNetwork, address_to_reachability: Dict[Address, AddressReachability], addresses: List[Address], ): hex_addrs = [to_checksum_address(addr) for addr in addresses] paths = token_network_model.get_paths( addresses[0], addresses[2], value=TokenAmount(10), max_paths=5, address_to_reachability=address_to_reachability, ) # 5 paths requested, but only 1 is available assert len(paths) == 1 assert paths[0] == { "path": [hex_addrs[0], hex_addrs[1], hex_addrs[2]], "estimated_fee": 0 }
def test_rebalancing_fee_calculation(): sample = calculate_imbalance_fees(TokenAmount(200), ProportionalFeeAmount(50_000)) # 5% assert sample is not None assert len(sample) == NUM_DISCRETISATION_POINTS assert all(0 <= x <= 200 for x, _ in sample) assert max(x for x, _ in sample) == 200 assert all(0 <= y <= 10 for _, y in sample) assert max(y for _, y in sample) == 10 # 5% of the 200 TokenAmount capacity sample = calculate_imbalance_fees(TokenAmount(100), ProportionalFeeAmount(20_000)) # 2% assert sample is not None assert len(sample) == NUM_DISCRETISATION_POINTS assert all(0 <= x <= 100 for x, _ in sample) assert max(x for x, _ in sample) == 100 assert all(0 <= y <= 2 for _, y in sample) assert max(y for _, y in sample) == 2 # 2% of the 100 TokenAmount capacity sample = calculate_imbalance_fees(TokenAmount(15), ProportionalFeeAmount(50_000)) # 5% assert sample is not None assert len(sample) == 16 assert all(0 <= x <= 16 for x, _ in sample) assert max(x for x, _ in sample) == 15 assert all(0 <= y <= 1 for _, y in sample) assert max(y for _, y in sample) == 1 # 5% of the 5 rounded up # test rounding of the max_balance_fee calculation sample = calculate_imbalance_fees(TokenAmount(1000), ProportionalFeeAmount(5_490)) # 0.549% assert sample is not None assert len(sample) == NUM_DISCRETISATION_POINTS assert all(0 <= x <= 1000 for x, _ in sample) assert max(x for x, _ in sample) == 1000 assert all(0 <= y <= 5 for _, y in sample) assert max(y for _, y in sample) == 5 # 5.49 is rounded to 5 sample = calculate_imbalance_fees(TokenAmount(1000), ProportionalFeeAmount(5_500)) # 0.55% assert sample is not None assert len(sample) == NUM_DISCRETISATION_POINTS assert all(0 <= x <= 1000 for x, _ in sample) assert max(x for x, _ in sample) == 1000 assert all(0 <= y <= 6 for _, y in sample) assert max(y for _, y in sample) == 6 # 5.5 is rounded to 6 # test cases where no imbalance fee is created assert calculate_imbalance_fees(TokenAmount(0), ProportionalFeeAmount(1)) is None assert calculate_imbalance_fees(TokenAmount(10), ProportionalFeeAmount(0)) is None
def test_setup_proxies_no_service_registry_but_pfs(): """ Test that if no service registry is provided but a manual pfs address is given then startup still works Regression test for https://github.com/raiden-network/raiden/issues/3740 """ chain_id = ChainID(5) config = RaidenConfig( chain_id=chain_id, environment_type=Environment.DEVELOPMENT, services=ServiceConfig(pathfinding_max_fee=100, pathfinding_iou_timeout=500, pathfinding_max_paths=5), ) contracts = load_deployed_contracts_data(config, chain_id) proxy_manager = MockProxyManager(node_address=make_address()) PFS_INFO = PFSInfo( url="my-pfs", price=TokenAmount(12), chain_id=ChainID(5), token_network_registry_address=to_canonical_address( contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]["address"]), user_deposit_address=user_deposit_address_test_default, confirmed_block_number=BlockNumber(1), payment_address=pfs_payment_address_default, message="This is your favorite pathfinding service", operator="John Doe", version="0.0.3", ) deployed_addresses = load_deployment_addresses_from_contracts(contracts) with patch.object(pathfinding, "get_pfs_info", return_value=PFS_INFO): services_bundle = services_bundle_from_contracts_deployment( config=config, proxy_manager=proxy_manager, deployed_addresses=deployed_addresses, routing_mode=RoutingMode.PFS, pathfinding_service_address="my-pfs", enable_monitoring=True, ) assert services_bundle
def test_action_monitoring_triggered_event_handler_does_not_trigger_monitor_call_when_nonce_to_small( # noqa context: Context, ): context = setup_state_with_closed_channel(context) event3 = ReceiveMonitoringNewBalanceProofEvent( token_network_address=DEFAULT_TOKEN_NETWORK_ADDRESS, channel_identifier=DEFAULT_CHANNEL_IDENTIFIER, reward_amount=TokenAmount(1), nonce=Nonce(5), ms_address=Address('C'), raiden_node_address=DEFAULT_PARTICIPANT2, block_number=BlockNumber(23), ) channel = context.db.get_channel(event3.token_network_address, event3.channel_identifier) assert channel assert channel.update_status is None monitor_new_balance_proof_event_handler(event3, context) # add MR to DB, with nonce being smaller than in event3 context.db.upsert_monitor_request( get_signed_monitor_request(nonce=Nonce(4))) event4 = ActionMonitoringTriggeredEvent( token_network_address=DEFAULT_TOKEN_NETWORK_ADDRESS, channel_identifier=DEFAULT_CHANNEL_IDENTIFIER, non_closing_participant=DEFAULT_PARTICIPANT2, ) channel = context.db.get_channel(event4.token_network_address, event4.channel_identifier) assert channel assert channel.update_status is not None assert channel.closing_tx_hash is None action_monitoring_triggered_event_handler(event4, context) assert context.db.channel_count() == 1 assert channel assert channel.closing_tx_hash is None
def test_monitor_new_balance_proof_event_handler_idempotency(context: Context): context = setup_state_with_closed_channel(context) new_balance_event = ReceiveMonitoringNewBalanceProofEvent( token_network_address=DEFAULT_TOKEN_NETWORK_ADDRESS, channel_identifier=DEFAULT_CHANNEL_IDENTIFIER, reward_amount=TokenAmount(1), nonce=Nonce(2), ms_address=Address(bytes([3] * 20)), raiden_node_address=DEFAULT_PARTICIPANT2, block_number=BlockNumber(23), ) channel = context.database.get_channel( new_balance_event.token_network_address, new_balance_event.channel_identifier) assert channel assert channel.update_status is None monitor_new_balance_proof_event_handler(new_balance_event, context) assert context.database.scheduled_event_count() == 1 assert context.database.channel_count() == 1 channel = context.database.get_channel( new_balance_event.token_network_address, new_balance_event.channel_identifier) assert channel assert channel.update_status is not None assert channel.update_status.nonce == 2 assert channel.update_status.update_sender_address == bytes([3] * 20) monitor_new_balance_proof_event_handler(new_balance_event, context) assert context.database.scheduled_event_count() == 1 assert context.database.channel_count() == 1 channel = context.database.get_channel( new_balance_event.token_network_address, new_balance_event.channel_identifier) assert channel assert channel.update_status is not None assert channel.update_status.nonce == 2 assert channel.update_status.update_sender_address == bytes([3] * 20)
def userdeposit_maybe_deposit( userdeposit_proxy: UserDeposit, mint_greenlets: Set[Greenlet], target_address: Address, minimum_effective_deposit: TokenAmount, maximum_funding: TokenAmount, ) -> None: """Make a deposit at the given `target_address`. The amount of tokens depends on the scenario definition's settings. If the target address has a sufficient deposit, this is a no-op. TODO: Allow setting max funding parameter, similar to the token `funding_min` setting. """ effective_balance = userdeposit_proxy.effective_balance( target_address, "latest") current_total_deposit = userdeposit_proxy.get_total_deposit( target_address, "latest") if maximum_funding < minimum_effective_deposit: raise ValueError( f"max_funding must be larger than minimum_effective_deposit, " f"otherwise the constraint can never be satisfied. Given " f"max_funding={maximum_funding} " f"minimum_effective_deposit={minimum_effective_deposit}") # Only do a deposit if the current effective balance is bellow the minimum. # When doing the deposit, top-up to max_funding to save transactions on the # next iterations. if effective_balance < minimum_effective_deposit: topup_amount = maximum_funding - effective_balance new_total_deposit = TokenAmount(current_total_deposit + topup_amount) # Wait for mint transactions, if necessary gevent.joinall(mint_greenlets, raise_error=True) userdeposit_proxy.deposit( target_address, new_total_deposit, userdeposit_proxy.client.get_confirmed_blockhash(), )
def test_receive_lockedtransfer_invalidrecipient(raiden_network, token_addresses, reveal_timeout, deposit): app0, app1 = raiden_network token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) payment_identifier = PaymentID(1) invalid_recipient = make_address() lock_amount = LockedAmount(10) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=Nonce(1), token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(0), locked_amount=lock_amount, recipient=invalid_recipient, locksroot=make_locksroot(), lock=Lock( amount=PaymentWithFeeAmount(lock_amount), expiration=expiration, secrethash=UNIT_SECRETHASH, ), target=app1.raiden.address, initiator=app0.raiden.address, signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[RouteMetadata(route=[app1.raiden.address])]), ) sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1) assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
def create_square_network_topology( token_network_state, our_address ) -> typing.Tuple[ TokenNetworkState, typing.List[typing.Address], typing.List[NettingChannelState] ]: address1 = factories.make_address() address2 = factories.make_address() address3 = factories.make_address() address4 = factories.make_address() # Create a network with the following topology # # our ----- 50 ----> (1) <------50------ # | | # | | # 100 (4) # | ^ # v | # (2) ----- 100 ---> (3) <-------100--- routes = [ factories.RouteProperties( address1=our_address, address2=address1, capacity1to2=TokenAmount(50) ), factories.RouteProperties( address1=our_address, address2=address2, capacity1to2=TokenAmount(100) ), factories.RouteProperties( address1=address4, address2=address1, capacity1to2=TokenAmount(50) ), factories.RouteProperties( address1=address2, address2=address3, capacity1to2=TokenAmount(100) ), factories.RouteProperties( address1=address3, address2=address4, capacity1to2=TokenAmount(100), capacity2to1=TokenAmount(100), ), ] new_state, channels = factories.create_network( token_network_state=token_network_state, our_address=our_address, routes=routes, block_number=factories.make_block_number(), ) return new_state, [address1, address2, address3, address4], channels
def pack_withdraw( canonical_identifier: CanonicalIdentifier, participant: Address, total_withdraw: WithdrawAmount, expiration_block: BlockExpiration, ) -> bytes: """Packs withdraw data to be signed Packs the given arguments in a byte array in the same configuration the contracts expect the signed data to have. """ return proofs.pack_withdraw_message( token_network_address=to_hex_address( canonical_identifier.token_network_address), chain_identifier=canonical_identifier.chain_identifier, channel_identifier=canonical_identifier.channel_identifier, participant=to_hex_address(participant), amount_to_withdraw=TokenAmount(total_withdraw), expiration_block=expiration_block, )
def get_paths( # pylint: disable=too-many-arguments token_network_model: TokenNetwork, address_to_reachability: Dict[Address, AddressReachability], addresses: List[Address], source_index: int = 0, target_index: int = 8, value: TokenAmount = TokenAmount(10), max_paths: int = 5, diversity_penalty: float = DIVERSITY_PEN_DEFAULT, ) -> List: paths = token_network_model.get_paths( diversity_penalty=diversity_penalty, source=addresses[source_index], target=addresses[target_index], value=value, max_paths=max_paths, address_to_reachability=address_to_reachability, ) index_paths = [addresses_to_indexes(p["path"], addresses) for p in paths] return index_paths
def test_receive_lockedtransfer_invalidsender( raiden_network: List[RaidenService], token_addresses, deposit, reveal_timeout ): app0, app1 = raiden_network token_address = token_addresses[0] other_key, other_address = make_privkey_address() token_network_address = views.get_token_network_address_by_token_address( views.state_from_raiden(app0), app0.default_registry.address, token_address ) assert token_network_address channel0 = get_channelstate(app0, app1, token_network_address) lock_amount = LockedAmount(10) expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=PaymentID(1), nonce=Nonce(1), token_network_address=token_network_address, token=token_address, channel_identifier=channel0.identifier, transferred_amount=TokenAmount(0), locked_amount=lock_amount, recipient=app0.address, locksroot=make_locksroot(), lock=Lock( amount=PaymentWithFeeAmount(lock_amount), expiration=expiration, secrethash=UNIT_SECRETHASH, ), target=TargetAddress(app0.address), initiator=InitiatorAddress(other_address), signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[RouteMetadata(route=[app0.address])]), ) sign_and_inject(mediated_transfer_message, LocalSigner(other_key), app0) assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
def calculate_imbalance_fees( channel_capacity: TokenAmount, proportional_imbalance_fee: ProportionalFeeAmount ) -> Optional[List[Tuple[TokenAmount, FeeAmount]]]: """ Calculates a U-shaped imbalance curve The penalty term takes the following value at the extrema: channel_capacity * (proportional_imbalance_fee / 1_000_000) """ assert channel_capacity >= 0 assert proportional_imbalance_fee >= 0 if proportional_imbalance_fee == 0: return None if channel_capacity == 0: return None MAXIMUM_SLOPE = 0.1 max_imbalance_fee = channel_capacity * proportional_imbalance_fee / 1e6 assert proportional_imbalance_fee / 1e6 <= MAXIMUM_SLOPE / 2, "Too high imbalance fee" # calculate function parameters s = MAXIMUM_SLOPE c = max_imbalance_fee o = channel_capacity / 2 b = s * o / c b = min(b, 10) # limit exponent to keep numerical stability a = c / o**b def f(x: TokenAmount) -> FeeAmount: return FeeAmount(int(round(a * abs(x - o)**b))) # calculate discrete function points num_base_points = min(NUM_DISCRETISATION_POINTS, channel_capacity + 1) x_values = linspace(TokenAmount(0), channel_capacity, num_base_points) y_values = [f(x) for x in x_values] return list(zip(x_values, y_values))