def _check_channel_state_for_withdraw( self, participant1, participant2, channel_identifier, withdraw_amount, ): participant_details = self.detail_participants( participant1, participant2, channel_identifier, ) if participant_details.our_details.withdrawn > withdraw_amount: raise WithdrawMismatch('Withdraw amount decreased') channel_state = self._get_channel_state( participant1=participant1, participant2=participant2, channel_identifier=channel_identifier, ) if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED): raise RaidenUnrecoverableError( f'Channel between participant {participant1} ' f'and {participant2} does not exist', ) elif channel_state == ChannelState.SETTLED: raise RaidenUnrecoverableError( 'A settled channel cannot be closed', ) elif channel_state == ChannelState.CLOSED: raise RaidenRecoverableError('Channel is already closed', )
def withdraw( self, channel_identifier: typing.ChannelID, partner: typing.Address, total_withdraw: int, partner_signature: typing.Address, signature: typing.Signature, ): log_details = { 'token_network': pex(self.address), 'node': pex(self.node_address), 'partner': pex(partner), 'total_withdraw': total_withdraw, 'partner_signature': encode_hex(partner_signature), 'signature': encode_hex(signature), } log.debug('setTotalWithdraw called', **log_details) self._check_for_outdated_channel( self.node_address, partner, channel_identifier, ) current_withdraw = self.detail_participant( channel_identifier, self.node_address, partner, ).withdrawn amount_to_withdraw = total_withdraw - current_withdraw if total_withdraw < current_withdraw: msg = ( f'Current withdraw ({current_withdraw}) is already larger ' f'than the requested total withdraw amount ({total_withdraw})', ) log.critical(f'setTotalWithdraw failed, {msg}', **log_details) raise WithdrawMismatch(msg) if amount_to_withdraw <= 0: msg = f'withdraw {amount_to_withdraw} must be greater than 0.' log.critical(f'setTotalWithdraw failed, {msg}', **log_details) raise ValueError(msg) with self.channel_operations_lock[partner]: transaction_hash = self.proxy.transact( 'setTotalWithdraw', channel_identifier, self.node_address, total_withdraw, partner_signature, signature, ) self.client.poll(transaction_hash) receipt_or_none = check_transaction_threw(self.client, transaction_hash) if receipt_or_none: log.critical('setTotalWithdraw failed', **log_details) self._check_channel_state_for_withdraw( self.node_address, partner, channel_identifier, total_withdraw, ) raise TransactionThrew('Withdraw', receipt_or_none) log.info('setTotalWithdraw successful', **log_details)
def set_total_channel_withdraw( self, registry_address: TokenNetworkRegistryAddress, token_address: TokenAddress, partner_address: Address, total_withdraw: WithdrawAmount, retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT, ) -> None: """ Set the `total_withdraw` in the channel with the peer at `partner_address` and the given `token_address`. Raises: InvalidBinaryAddress: If either token_address or partner_address is not 20 bytes long. RaidenUnrecoverableError: May happen for multiple reasons: - During preconditions checks, if the channel was not open at the time of the approve_and_set_total_deposit call. - If the transaction fails during gas estimation or if a previous withdraw transaction with the same value was already mined. DepositMismatch: The total withdraw amount did not increase. """ chain_state = views.state_from_raiden(self.raiden) token_addresses = views.get_token_identifiers(chain_state, registry_address) channel_state = views.get_channelstate_for( chain_state=chain_state, token_network_registry_address=registry_address, token_address=token_address, partner_address=partner_address, ) if not is_binary_address(token_address): raise InvalidBinaryAddress( "Expected binary address format for token in channel deposit") if not is_binary_address(partner_address): raise InvalidBinaryAddress( "Expected binary address format for partner in channel deposit" ) if token_address not in token_addresses: raise UnknownTokenAddress("Unknown token address") if channel_state is None: raise NonexistingChannel( "No channel with partner_address for the given token") if total_withdraw <= channel_state.our_total_withdraw: raise WithdrawMismatch( f"Total withdraw {total_withdraw} did not increase") current_balance = channel.get_balance( sender=channel_state.our_state, receiver=channel_state.partner_state) amount_to_withdraw = total_withdraw - channel_state.our_total_withdraw if amount_to_withdraw > current_balance: raise InsufficientFunds( "The withdraw of {} is bigger than the current balance of {}". format(amount_to_withdraw, current_balance)) self.raiden.withdraw( canonical_identifier=channel_state.canonical_identifier, total_withdraw=total_withdraw) waiting.wait_for_withdraw_complete( raiden=self.raiden, canonical_identifier=channel_state.canonical_identifier, total_withdraw=total_withdraw, retry_timeout=retry_timeout, )