Exemplo n.º 1
0
 def __init__(self, raiden_api):
     self.raiden_api = raiden_api
     self.channel_schema = ChannelSchema()
     self.channel_list_schema = ChannelListSchema()
     self.address_list_schema = AddressListSchema()
     self.partner_per_token_list_schema = PartnersPerTokenListSchema()
     self.transfer_schema = TransferSchema()
Exemplo n.º 2
0
class RestAPI(object):
    """
    This wraps around the actual RaidenAPI in raiden_service.
    It will provide the additional, neccessary RESTful logic and
    the proper JSON-encoding of the Objects provided by the RaidenAPI
    """
    version = 1

    def __init__(self, raiden_api):
        self.raiden_api = raiden_api
        self.channel_schema = ChannelSchema()
        self.channel_list_schema = ChannelListSchema()
        self.tokens_list_schema = TokensListSchema()
        self.partner_per_token_list_schema = PartnersPerTokenListSchema()
        self.transfer_schema = TransferSchema()

    def open(self,
             partner_address,
             token_address,
             settle_timeout,
             balance=None):
        raiden_service_result = self.raiden_api.open(token_address,
                                                     partner_address,
                                                     settle_timeout)

        if balance:
            # make initial deposit
            raiden_service_result = self.raiden_api.deposit(
                token_address, partner_address, balance)

        result = self.channel_schema.dumps(
            channel_to_api_dict(raiden_service_result))
        return result

    def deposit(self, token_address, partner_address, amount):

        raiden_service_result = self.raiden_api.deposit(
            token_address, partner_address, amount)

        result = self.channel_schema.dumps(
            channel_to_api_dict(raiden_service_result))
        return result

    def close(self, token_address, partner_address):

        raiden_service_result = self.raiden_api.close(token_address,
                                                      partner_address)

        result = self.channel_schema.dumps(
            channel_to_api_dict(raiden_service_result))
        return result

    def get_channel_list(self, token_address=None, partner_address=None):
        raiden_service_result = self.raiden_api.get_channel_list(
            token_address, partner_address)
        assert isinstance(raiden_service_result, list)

        channel_list = ChannelList(raiden_service_result)
        result = self.channel_list_schema.dumps(channel_list)
        return result

    def get_tokens_list(self):
        raiden_service_result = self.raiden_api.get_tokens_list()
        assert isinstance(raiden_service_result, list)

        new_list = []
        for result in raiden_service_result:
            new_list.append({'address': result})

        tokens_list = TokensList(new_list)
        result = self.tokens_list_schema.dumps(tokens_list)
        return result

    def get_network_events(self, from_block, to_block):
        raiden_service_result = self.raiden_api.get_network_events(
            from_block, to_block)
        return normalize_events_list(raiden_service_result)

    def get_token_network_events(self, token_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_token_network_events(
            token_address, from_block, to_block)
        return normalize_events_list(raiden_service_result)

    def get_channel_events(self, channel_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_channel_events(
            channel_address, from_block, to_block)
        return normalize_events_list(raiden_service_result)

    def get_channel(self, channel_address):
        channel = self.raiden_api.get_channel(channel_address)
        return self.channel_schema.dumps(channel_to_api_dict(channel))

    def get_partners_by_token(self, token_address):
        return_list = []
        raiden_service_result = self.raiden_api.get_channel_list(token_address)
        for result in raiden_service_result:
            return_list.append({
                'partner_address':
                result.partner_address,
                'channel':
                url_for(
                    # TODO: Somehow nicely parameterize this for future versions
                    'v1_resources.channelsresourcebychanneladdress',
                    channel_address=result.channel_address),
            })

        schema_list = PartnersPerTokenList(return_list)
        result = self.partner_per_token_list_schema.dumps(schema_list)
        return result

    def initiate_transfer(self, token_address, target_address, amount,
                          identifier):

        if identifier is None:
            identifier = self.raiden_api.create_default_identifier(
                target_address, token_address)

        try:
            self.raiden_api.transfer(token_address=token_address,
                                     target=target_address,
                                     amount=amount,
                                     identifier=identifier)

            transfer = {
                'initiator_address': self.raiden_api.raiden.address,
                'token_address': token_address,
                'target_address': target_address,
                'amount': amount,
                'identifier': identifier,
            }
            return self.transfer_schema.dumps(transfer)
        except (InvalidAmount, InvalidAddress, NoPathError) as e:
            return make_response(str(e), httplib.CONFLICT)

    def patch_channel(self, channel_address, balance=None, state=None):
        if balance is not None and state is not None:
            return make_response(
                'Can not update balance and change channel state at the same time',
                httplib.CONFLICT,
            )
        elif balance is None and state is None:
            return make_response(
                'Nothing to do. Should either provide \'balance\' or \'state\' argument',
                httplib.BAD_REQUEST,
            )

        # find the channel
        channel = self.raiden_api.get_channel(channel_address)
        current_state = channel.state
        # if we patch with `balance` it's a deposit
        if balance is not None:
            if current_state != CHANNEL_STATE_OPENED:
                return make_response(
                    "Can't deposit on a closed channel",
                    httplib.CONFLICT,
                )
            raiden_service_result = self.raiden_api.deposit(
                channel.token_address, channel.partner_address, balance)
            return self.channel_schema.dumps(
                channel_to_api_dict(raiden_service_result))

        else:
            if state == CHANNEL_STATE_CLOSED:
                if current_state != CHANNEL_STATE_OPENED:
                    return make_response(
                        httplib.CONFLICT,
                        'Attempted to close an already closed channel')
                raiden_service_result = self.raiden_api.close(
                    channel.token_address, channel.partner_address)
                return self.channel_schema.dumps(
                    channel_to_api_dict(raiden_service_result))
            elif state == CHANNEL_STATE_SETTLED:
                if current_state == CHANNEL_STATE_SETTLED or current_state == CHANNEL_STATE_OPENED:
                    return make_response(
                        'Attempted to settle a channel at its {} state'.format(
                            current_state),
                        httplib.CONFLICT,
                    )
                raiden_service_result = self.raiden_api.settle(
                    channel.token_address, channel.partner_address)
                return self.channel_schema.dumps(
                    channel_to_api_dict(raiden_service_result))
            else:
                # should never happen, channel_state is validated in the schema
                return make_response(
                    'Provided invalid channel state {}'.format(state),
                    httplib.BAD_REQUEST,
                )

    def token_swap(self, target_address, identifier, role, sending_token,
                   sending_amount, receiving_token, receiving_amount):

        if role == 'maker':
            self.raiden_api.token_swap(
                from_token=sending_token,
                from_amount=sending_amount,
                to_token=receiving_token,
                to_amount=receiving_amount,
                target_address=target_address,
            )
        elif role == 'taker':
            self.raiden_api.expect_token_swap(
                identifier=identifier,
                from_token=sending_token,
                from_amount=sending_amount,
                to_token=receiving_token,
                to_amount=receiving_amount,
                target_address=target_address,
            )
        else:
            # should never happen, role is validated in the schema
            return make_response(
                'Provided invalid token swap role {}'.format(role),
                httplib.BAD_REQUEST,
            )
Exemplo n.º 3
0
class RestAPI:
    """
    This wraps around the actual RaidenAPI in api/python.
    It will provide the additional, neccessary RESTful logic and
    the proper JSON-encoding of the Objects provided by the RaidenAPI
    """
    version = 1

    def __init__(self, raiden_api):
        self.raiden_api = raiden_api
        self.channel_schema = ChannelSchema()
        self.channel_list_schema = ChannelListSchema()
        self.address_list_schema = AddressListSchema()
        self.partner_per_token_list_schema = PartnersPerTokenListSchema()
        self.transfer_schema = TransferSchema()

    def get_our_address(self):
        return api_response(
            result=dict(our_address=to_checksum_address(self.raiden_api.address)),
        )

    def register_token(self, registry_address, token_address):
        try:
            manager_address = self.raiden_api.token_network_register(
                registry_address,
                token_address,
            )
        except (InvalidAddress, AlreadyRegisteredTokenAddress, TransactionThrew) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        return api_response(
            result=dict(channel_manager_address=to_checksum_address(manager_address)),
            status_code=HTTPStatus.CREATED,
        )

    def open(
            self,
            registry_address,
            partner_address,
            token_address,
            settle_timeout=None,
            reveal_timeout=None,
            balance=None,
    ):

        try:
            self.raiden_api.channel_open(
                registry_address,
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, NoTokenManager, DuplicatedChannelError) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        if balance:
            # make initial deposit
            try:
                self.raiden_api.set_total_channel_deposit(
                    registry_address,
                    token_address,
                    partner_address,
                    balance,
                )
            except EthNodeCommunicationError as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.REQUEST_TIMEOUT,
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED,
                )

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(self.raiden_api.raiden),
            registry_address,
            token_address,
            partner_address,
        )

        result = self.channel_schema.dump(channelstate_to_api_dict(channel_state))

        return api_response(
            result=checksummed_response_dict(result.data),
            status_code=HTTPStatus.CREATED,
        )

    def close(self, registry_address, token_address, partner_address):
        try:
            raiden_service_result = self.raiden_api.channel_close(
                registry_address,
                token_address,
                partner_address,
            )
        except ChannelBusyError as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        result = self.channel_schema.dump(channelstate_to_api_dict(raiden_service_result))
        return api_response(result=checksummed_response_dict(result.data))

    def connect(
            self,
            registry_address,
            token_address,
            funds,
            initial_channel_target=None,
            joinable_funds_target=None,
    ):

        try:
            self.raiden_api.token_network_connect(
                registry_address,
                token_address,
                funds,
                initial_channel_target,
                joinable_funds_target,
            )
        except EthNodeCommunicationError as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.REQUEST_TIMEOUT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        return api_response(
            result=dict(),
            status_code=HTTPStatus.NO_CONTENT,
        )

    def leave(self, registry_address, token_address, only_receiving):
        closed_channels = self.raiden_api.token_network_leave(
            registry_address,
            token_address,
            only_receiving,
        )
        closed_channels = [channel_state.identifier for channel_state in closed_channels]
        channel_addresses_list = AddressList(closed_channels)
        result = self.address_list_schema.dump(channel_addresses_list)
        return api_response(result=checksummed_response_dict(result.data))

    def get_connection_managers_info(self, registry_address):
        """Get a dict whose keys are token addresses and whose values are
        open channels, funds of last request, sum of deposits and number of channels"""
        connection_managers = dict()

        for token in self.raiden_api.get_tokens_list(registry_address):
            try:
                connection_manager = self.raiden_api.raiden.connection_manager_for_token(
                    registry_address,
                    token,
                )
            except InvalidAddress:
                connection_manager = None

            open_channels = views.get_channelstate_open(
                views.state_from_raiden(self.raiden_api.raiden),
                registry_address,
                token,
            )
            if connection_manager is not None and open_channels:
                connection_managers[to_checksum_address(connection_manager.token_address)] = {
                    'funds': connection_manager.funds,
                    'sum_deposits': views.get_our_capacity_for_token_network(
                        views.state_from_raiden(self.raiden_api.raiden),
                        registry_address,
                        token,
                    ),
                    'channels': len(open_channels),
                }

        return connection_managers

    def get_channel_list(self, registry_address, token_address=None, partner_address=None):
        raiden_service_result = self.raiden_api.get_channel_list(
            registry_address,
            token_address,
            partner_address,
        )
        assert isinstance(raiden_service_result, list)

        channel_list = ChannelList(raiden_service_result)
        result = self.channel_list_schema.dump(channel_list)
        return api_response(result=checksummed_response_list(result.data))

    def get_tokens_list(self, registry_address):
        raiden_service_result = self.raiden_api.get_tokens_list(registry_address)
        assert isinstance(raiden_service_result, list)
        tokens_list = AddressList(raiden_service_result)
        result = self.address_list_schema.dump(tokens_list)
        return api_response(result=checksummed_response_list(result.data))

    def get_network_events(self, registry_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_network_events(
            registry_address,
            from_block,
            to_block,
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_token_network_events(self, token_address, from_block, to_block):
        try:
            raiden_service_result = self.raiden_api.get_token_network_events(
                token_address,
                from_block,
                to_block,
            )
            return api_response(result=normalize_events_list(raiden_service_result))
        except UnknownTokenAddress as e:
            return api_error(str(e), status_code=HTTPStatus.NOT_FOUND)

    def get_channel_events(self, channel_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_channel_events(
            channel_address, from_block, to_block,
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_channel(self, registry_address, channel_address):
        channel_state = self.raiden_api.get_channel(registry_address, channel_address)
        result = self.channel_schema.dump(channelstate_to_api_dict(channel_state))
        return api_response(result=checksummed_response_dict(result.data))

    def get_partners_by_token(self, registry_address, token_address):
        return_list = []
        raiden_service_result = self.raiden_api.get_channel_list(
            registry_address,
            token_address,
        )
        for result in raiden_service_result:
            return_list.append({
                'partner_address': result.partner_state.address,
                'channel': url_for(
                    # TODO: Somehow nicely parameterize this for future versions
                    'v1_resources.channelsresourcebychanneladdress',
                    channel_address=result.identifier,
                ),
            })

        schema_list = PartnersPerTokenList(return_list)
        result = self.partner_per_token_list_schema.dump(schema_list)
        return api_response(result=checksummed_response_list(result.data))

    def initiate_transfer(
            self,
            registry_address,
            token_address,
            target_address,
            amount,
            identifier,
    ):

        if identifier is None:
            identifier = create_default_identifier()

        try:
            transfer_result = self.raiden_api.transfer(
                registry_address=registry_address,
                token_address=token_address,
                target=target_address,
                amount=amount,
                identifier=identifier,
            )
        except (InvalidAmount, InvalidAddress) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if transfer_result is False:
            return api_error(
                errors="Payment couldn't be completed "
                "(insufficient funds or no route to target).",
                status_code=HTTPStatus.CONFLICT,
            )

        transfer = {
            'initiator_address': self.raiden_api.address,
            'registry_address': registry_address,
            'token_address': token_address,
            'target_address': target_address,
            'amount': amount,
            'identifier': identifier,
        }
        result = self.transfer_schema.dump(transfer)
        return api_response(result=checksummed_response_dict(result.data))

    def _deposit(self, registry_address, channel_state, total_deposit):
        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            return api_error(
                errors="Can't set total deposit on a closed channel",
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            self.raiden_api.set_total_channel_deposit(
                registry_address,
                channel_state.token_address,
                channel_state.partner_state.address,
                total_deposit,
            )
        except ChannelBusyError as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        updated_channel_state = self.raiden_api.get_channel(
            registry_address,
            channel_state.identifier,
        )

        result = self.channel_schema.dump(channelstate_to_api_dict(updated_channel_state))
        return api_response(result=checksummed_response_dict(result.data))

    def _close(self, registry_address, channel_state):
        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            return api_error(
                errors='Attempted to close an already closed channel',
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            self.raiden_api.channel_close(
                registry_address,
                channel_state.token_address,
                channel_state.partner_state.address,
            )
        except ChannelBusyError as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        updated_channel_state = self.raiden_api.get_channel(
            registry_address,
            channel_state.identifier,
        )

        result = self.channel_schema.dump(channelstate_to_api_dict(updated_channel_state))

        return api_response(result=checksummed_response_dict(result.data))

    def patch_channel(self, registry_address, channel_address, total_deposit=None, state=None):
        if total_deposit is not None and state is not None:
            return api_error(
                errors="Can not update a channel's total deposit and state at the same time",
                status_code=HTTPStatus.CONFLICT,
            )

        if total_deposit is None and state is None:
            return api_error(
                errors="Nothing to do. Should either provide 'total_deposit' or 'state' argument",
                status_code=HTTPStatus.BAD_REQUEST,
            )

        try:
            channel_state = self.raiden_api.get_channel(
                registry_address,
                channel_address,
            )

        except ChannelNotFound:
            return api_error(
                errors='Requested channel {} not found'.format(
                    to_checksum_address(channel_address),
                ),
                status_code=HTTPStatus.CONFLICT,
            )

        if total_deposit is not None:
            result = self._deposit(registry_address, channel_state, total_deposit)

        elif state == CHANNEL_STATE_CLOSED:
            result = self._close(registry_address, channel_state)

        else:  # should never happen, channel_state is validated in the schema
            result = api_error(
                errors='Provided invalid channel state {}'.format(state),
                status_code=HTTPStatus.BAD_REQUEST,
            )

        return result
Exemplo n.º 4
0
class RestAPI(object):
    """
    This wraps around the actual RaidenAPI in api/python.
    It will provide the additional, neccessary RESTful logic and
    the proper JSON-encoding of the Objects provided by the RaidenAPI
    """
    version = 1

    def __init__(self, raiden_api):
        self.raiden_api = raiden_api
        self.channel_schema = ChannelSchema()
        self.channel_list_schema = ChannelListSchema()
        self.address_list_schema = AddressListSchema()
        self.partner_per_token_list_schema = PartnersPerTokenListSchema()
        self.transfer_schema = TransferSchema()

    def get_our_address(self):
        return api_response(result=dict(our_address=address_encoder(self.raiden_api.address)))

    def register_token(self, token_address):
        manager_address = self.raiden_api.manager_address_if_token_registered(token_address)

        if manager_address is not None:
            return api_error(errors='Token is already registered', status_code=httplib.CONFLICT)

        if manager_address is None:
            manager_address = self.raiden_api.register_token(token_address)

        return api_response(
            result=dict(channel_manager_address=address_encoder(manager_address)),
            status_code=httplib.CREATED
        )

    def open(
            self,
            partner_address,
            token_address,
            settle_timeout=None,
            reveal_timeout=None,
            balance=None):
        try:
            raiden_service_result = self.raiden_api.open(
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, NoTokenManager, DuplicatedChannelError) as e:
            return api_error(
                errors=str(e),
                status_code=httplib.CONFLICT
            )

        if balance:
            # make initial deposit
            try:
                raiden_service_result = self.raiden_api.deposit(
                    token_address,
                    partner_address,
                    balance
                )
            except EthNodeCommunicationError as e:
                return api_error(
                    errors=str(e),
                    status_code=httplib.REQUEST_TIMEOUT
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=httplib.PAYMENT_REQUIRED
                )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(
            result=result.data,
            status_code=httplib.CREATED
        )

    def deposit(self, token_address, partner_address, amount):
        try:
            raiden_service_result = self.raiden_api.deposit(
                token_address,
                partner_address,
                amount
            )
        except EthNodeCommunicationError as e:
            return api_error(
                errors=str(e),
                status_code=httplib.REQUEST_TIMEOUT
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=httplib.PAYMENT_REQUIRED
            )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def close(self, token_address, partner_address):

        raiden_service_result = self.raiden_api.close(
            token_address,
            partner_address
        )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def connect(
            self,
            token_address,
            funds,
            initial_channel_target=None,
            joinable_funds_target=None):

        try:
            self.raiden_api.connect_token_network(
                token_address,
                funds,
                initial_channel_target,
                joinable_funds_target
            )
        except EthNodeCommunicationError as e:
            return api_error(
                errors=str(e),
                status_code=httplib.REQUEST_TIMEOUT
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=httplib.PAYMENT_REQUIRED
            )

        return api_response(
            result=dict(),
            status_code=httplib.NO_CONTENT
        )

    def leave(self, token_address, only_receiving):
        closed_channels = self.raiden_api.leave_token_network(token_address, only_receiving)
        closed_channels = [channel.channel_address for channel in closed_channels]
        channel_addresses_list = AddressList(closed_channels)
        result = self.address_list_schema.dump(channel_addresses_list)
        return api_response(result=result.data)

    def get_connection_managers_info(self):
        raiden_service_result = self.raiden_api.get_connection_managers_info()
        assert isinstance(raiden_service_result, dict)
        # encode token addresses indexes
        result = {
            address_encoder(token_address): info
            for token_address, info in raiden_service_result.iteritems()
        }
        return api_response(result=result)

    def get_channel_list(self, token_address=None, partner_address=None):
        raiden_service_result = self.raiden_api.get_channel_list(token_address, partner_address)
        assert isinstance(raiden_service_result, list)

        channel_list = ChannelList(raiden_service_result)
        result = self.channel_list_schema.dump(channel_list)
        return api_response(result=result.data)

    def get_tokens_list(self):
        raiden_service_result = self.raiden_api.get_tokens_list()
        assert isinstance(raiden_service_result, list)
        tokens_list = AddressList(raiden_service_result)
        result = self.address_list_schema.dump(tokens_list)
        return api_response(result=result.data)

    def get_network_events(self, from_block, to_block):
        raiden_service_result = self.raiden_api.get_network_events(
            from_block, to_block
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_token_network_events(self, token_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_token_network_events(
            token_address, from_block, to_block
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_channel_events(self, channel_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_channel_events(
            channel_address, from_block, to_block
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_channel(self, channel_address):
        channel = self.raiden_api.get_channel(channel_address)
        result = self.channel_schema.dump(channel_to_api_dict(channel))
        return api_response(result=result.data)

    def get_partners_by_token(self, token_address):
        return_list = []
        raiden_service_result = self.raiden_api.get_channel_list(token_address)
        for result in raiden_service_result:
            return_list.append({
                'partner_address': result.partner_address,
                'channel': url_for(
                    # TODO: Somehow nicely parameterize this for future versions
                    'v1_resources.channelsresourcebychanneladdress',
                    channel_address=result.channel_address
                ),
            })

        schema_list = PartnersPerTokenList(return_list)
        result = self.partner_per_token_list_schema.dump(schema_list)
        return api_response(result=result.data)

    def initiate_transfer(self, token_address, target_address, amount, identifier):

        if identifier is None:
            identifier = create_default_identifier()

        try:
            transfer_result = self.raiden_api.transfer(
                token_address=token_address,
                target=target_address,
                amount=amount,
                identifier=identifier
            )
        except (InvalidAmount, InvalidAddress, NoPathError) as e:
            return api_error(
                errors=str(e),
                status_code=httplib.CONFLICT
            )
        except (InsufficientFunds) as e:
            return api_error(
                errors=str(e),
                status_code=httplib.PAYMENT_REQUIRED
            )

        if transfer_result is False:
            return api_error(
                errors="Payment couldn't be completed "
                "(insufficient funds or no route to target).",
                status_code=httplib.CONFLICT
            )

        transfer = {
            'initiator_address': self.raiden_api.raiden.address,
            'token_address': token_address,
            'target_address': target_address,
            'amount': amount,
            'identifier': identifier,
        }
        result = self.transfer_schema.dump(transfer)
        return api_response(result=result.data)

    def _deposit(self, channel, balance):
        if channel.state != CHANNEL_STATE_OPENED:
            return api_error(
                errors="Can't deposit on a closed channel",
                status_code=httplib.CONFLICT,
            )

        try:
            raiden_service_result = self.raiden_api.deposit(
                channel.token_address,
                channel.partner_address,
                balance
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=httplib.PAYMENT_REQUIRED
            )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def _close(self, channel):
        if channel.state != CHANNEL_STATE_OPENED:
            return api_error(
                errors='Attempted to close an already closed channel',
                status_code=httplib.CONFLICT,
            )

        raiden_service_result = self.raiden_api.close(
            channel.token_address,
            channel.partner_address
        )
        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def _settle(self, channel):
        if channel.state != CHANNEL_STATE_CLOSED:
            return api_error(
                errors='Attempted to settle a channel at its {} state'.format(
                    channel.state,
                ),
                status_code=httplib.CONFLICT,
            )

        try:
            raiden_service_result = self.raiden_api.settle(
                channel.token_address,
                channel.partner_address
            )
        except InvalidState:
            return api_error(
                errors='Settlement period is not yet over',
                status_code=httplib.CONFLICT,
            )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def patch_channel(self, channel_address, balance=None, state=None):
        if balance is not None and state is not None:
            return api_error(
                errors='Can not update balance and change channel state at the same time',
                status_code=httplib.CONFLICT,
            )

        if balance is None and state is None:
            return api_error(
                errors="Nothing to do. Should either provide 'balance' or 'state' argument",
                status_code=httplib.BAD_REQUEST,
            )

        try:
            channel = self.raiden_api.get_channel(channel_address)
        except ChannelNotFound:
            return api_error(
                errors='Requested channel {} not found'.format(address_encoder(channel_address)),
                status_code=httplib.CONFLICT,
            )

        if balance is not None:
            result = self._deposit(channel, balance)

        elif state == CHANNEL_STATE_CLOSED:
            result = self._close(channel)

        elif state == CHANNEL_STATE_SETTLED:
            result = self._settle(channel)

        else:  # should never happen, channel_state is validated in the schema
            result = api_error(
                errors='Provided invalid channel state {}'.format(state),
                status_code=httplib.BAD_REQUEST,
            )

        return result

    def token_swap(
            self,
            target_address,
            identifier,
            role,
            sending_token,
            sending_amount,
            receiving_token,
            receiving_amount):

        if role == 'maker':
            self.raiden_api.token_swap(
                identifier=identifier,
                maker_token=sending_token,
                maker_amount=sending_amount,
                maker_address=self.raiden_api.address,
                taker_token=receiving_token,
                taker_amount=receiving_amount,
                taker_address=target_address,
            )
        elif role == 'taker':
            self.raiden_api.expect_token_swap(
                identifier=identifier,
                maker_token=receiving_token,
                maker_amount=receiving_amount,
                maker_address=target_address,
                taker_token=sending_token,
                taker_amount=sending_amount,
                taker_address=self.raiden_api.address
            )
        else:
            # should never happen, role is validated in the schema
            return api_error(
                errors='Provided invalid token swap role {}'.format(role),
                status_code=httplib.BAD_REQUEST,
            )

        return api_response(result=dict(), status_code=httplib.CREATED)
Exemplo n.º 5
0
class RestAPI:
    """
    This wraps around the actual RaidenAPI in api/python.
    It will provide the additional, neccessary RESTful logic and
    the proper JSON-encoding of the Objects provided by the RaidenAPI
    """
    version = 1

    def __init__(self, raiden_api):
        self.raiden_api = raiden_api
        self.channel_schema = ChannelSchema()
        self.channel_list_schema = ChannelListSchema()
        self.address_list_schema = AddressListSchema()
        self.partner_per_token_list_schema = PartnersPerTokenListSchema()
        self.transfer_schema = TransferSchema()

    def get_our_address(self):
        return api_response(result=dict(our_address=address_encoder(self.raiden_api.address)))

    def register_token(self, token_address):
        manager_address = self.raiden_api.manager_address_if_token_registered(token_address)

        if manager_address is not None:
            return api_error(
                errors='Token is already registered',
                status_code=HTTPStatus.CONFLICT
            )

        if manager_address is None:
            manager_address = self.raiden_api.register_token(token_address)

        return api_response(
            result=dict(channel_manager_address=address_encoder(manager_address)),
            status_code=HTTPStatus.CREATED
        )

    def open(
            self,
            partner_address,
            token_address,
            settle_timeout=None,
            reveal_timeout=None,
            balance=None):
        try:
            raiden_service_result = self.raiden_api.open(
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, NoTokenManager, DuplicatedChannelError) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT
            )

        if balance:
            # make initial deposit
            try:
                raiden_service_result = self.raiden_api.deposit(
                    token_address,
                    partner_address,
                    balance
                )
            except EthNodeCommunicationError as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.REQUEST_TIMEOUT
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED
                )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(
            result=result.data,
            status_code=HTTPStatus.CREATED
        )

    def deposit(self, token_address, partner_address, amount):
        try:
            raiden_service_result = self.raiden_api.deposit(
                token_address,
                partner_address,
                amount
            )
        except EthNodeCommunicationError as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.REQUEST_TIMEOUT
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED
            )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def close(self, token_address, partner_address):

        raiden_service_result = self.raiden_api.close(
            token_address,
            partner_address
        )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def connect(
            self,
            token_address,
            funds,
            initial_channel_target=None,
            joinable_funds_target=None):

        try:
            self.raiden_api.connect_token_network(
                token_address,
                funds,
                initial_channel_target,
                joinable_funds_target
            )
        except EthNodeCommunicationError as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.REQUEST_TIMEOUT
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED
            )

        return api_response(
            result=dict(),
            status_code=HTTPStatus.NO_CONTENT
        )

    def leave(self, token_address, only_receiving):
        closed_channels = self.raiden_api.leave_token_network(token_address, only_receiving)
        closed_channels = [channel.channel_address for channel in closed_channels]
        channel_addresses_list = AddressList(closed_channels)
        result = self.address_list_schema.dump(channel_addresses_list)
        return api_response(result=result.data)

    def get_connection_managers_info(self):
        raiden_service_result = self.raiden_api.get_connection_managers_info()
        assert isinstance(raiden_service_result, dict)
        # encode token addresses indexes
        result = {
            address_encoder(token_address): info
            for token_address, info in raiden_service_result.items()
        }
        return api_response(result=result)

    def get_channel_list(self, token_address=None, partner_address=None):
        raiden_service_result = self.raiden_api.get_channel_list(token_address, partner_address)
        assert isinstance(raiden_service_result, list)

        channel_list = ChannelList(raiden_service_result)
        result = self.channel_list_schema.dump(channel_list)
        return api_response(result=result.data)

    def get_tokens_list(self):
        raiden_service_result = self.raiden_api.get_tokens_list()
        assert isinstance(raiden_service_result, list)
        tokens_list = AddressList(raiden_service_result)
        result = self.address_list_schema.dump(tokens_list)
        return api_response(result=result.data)

    def get_network_events(self, from_block, to_block):
        raiden_service_result = self.raiden_api.get_network_events(
            from_block, to_block
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_token_network_events(self, token_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_token_network_events(
            token_address, from_block, to_block
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_channel_events(self, channel_address, from_block, to_block):
        raiden_service_result = self.raiden_api.get_channel_events(
            channel_address, from_block, to_block
        )
        return api_response(result=normalize_events_list(raiden_service_result))

    def get_channel(self, channel_address):
        channel = self.raiden_api.get_channel(channel_address)
        result = self.channel_schema.dump(channel_to_api_dict(channel))
        return api_response(result=result.data)

    def get_partners_by_token(self, token_address):
        return_list = []
        raiden_service_result = self.raiden_api.get_channel_list(token_address)
        for result in raiden_service_result:
            return_list.append({
                'partner_address': result.partner_address,
                'channel': url_for(
                    # TODO: Somehow nicely parameterize this for future versions
                    'v1_resources.channelsresourcebychanneladdress',
                    channel_address=result.channel_address
                ),
            })

        schema_list = PartnersPerTokenList(return_list)
        result = self.partner_per_token_list_schema.dump(schema_list)
        return api_response(result=result.data)

    def initiate_transfer(self, token_address, target_address, amount, identifier):

        if identifier is None:
            identifier = create_default_identifier()

        try:
            transfer_result = self.raiden_api.transfer(
                token_address=token_address,
                target=target_address,
                amount=amount,
                identifier=identifier
            )
        except (InvalidAmount, InvalidAddress, NoPathError) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED
            )

        if transfer_result is False:
            return api_error(
                errors="Payment couldn't be completed "
                "(insufficient funds or no route to target).",
                status_code=HTTPStatus.CONFLICT
            )

        transfer = {
            'initiator_address': self.raiden_api.raiden.address,
            'token_address': token_address,
            'target_address': target_address,
            'amount': amount,
            'identifier': identifier,
        }
        result = self.transfer_schema.dump(transfer)
        return api_response(result=result.data)

    def _deposit(self, channel, balance):
        if channel.state != CHANNEL_STATE_OPENED:
            return api_error(
                errors="Can't deposit on a closed channel",
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            raiden_service_result = self.raiden_api.deposit(
                channel.token_address,
                channel.partner_address,
                balance
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED
            )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def _close(self, channel):
        if channel.state != CHANNEL_STATE_OPENED:
            return api_error(
                errors='Attempted to close an already closed channel',
                status_code=HTTPStatus.CONFLICT,
            )

        raiden_service_result = self.raiden_api.close(
            channel.token_address,
            channel.partner_address
        )
        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def _settle(self, channel):
        if channel.state != CHANNEL_STATE_CLOSED:
            return api_error(
                errors='Attempted to settle a channel at its {} state'.format(
                    channel.state,
                ),
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            raiden_service_result = self.raiden_api.settle(
                channel.token_address,
                channel.partner_address
            )
        except InvalidState:
            return api_error(
                errors='Settlement period is not yet over',
                status_code=HTTPStatus.CONFLICT,
            )

        result = self.channel_schema.dump(channel_to_api_dict(raiden_service_result))
        return api_response(result=result.data)

    def patch_channel(self, channel_address, balance=None, state=None):
        if balance is not None and state is not None:
            return api_error(
                errors='Can not update balance and change channel state at the same time',
                status_code=HTTPStatus.CONFLICT,
            )

        if balance is None and state is None:
            return api_error(
                errors="Nothing to do. Should either provide 'balance' or 'state' argument",
                status_code=HTTPStatus.BAD_REQUEST,
            )

        try:
            channel = self.raiden_api.get_channel(channel_address)
        except ChannelNotFound:
            return api_error(
                errors='Requested channel {} not found'.format(address_encoder(channel_address)),
                status_code=HTTPStatus.CONFLICT,
            )

        if balance is not None:
            result = self._deposit(channel, balance)

        elif state == CHANNEL_STATE_CLOSED:
            result = self._close(channel)

        elif state == CHANNEL_STATE_SETTLED:
            result = self._settle(channel)

        else:  # should never happen, channel_state is validated in the schema
            result = api_error(
                errors='Provided invalid channel state {}'.format(state),
                status_code=HTTPStatus.BAD_REQUEST,
            )

        return result

    def token_swap(
            self,
            target_address,
            identifier,
            role,
            sending_token,
            sending_amount,
            receiving_token,
            receiving_amount):

        if role == 'maker':
            self.raiden_api.token_swap(
                identifier=identifier,
                maker_token=sending_token,
                maker_amount=sending_amount,
                maker_address=self.raiden_api.address,
                taker_token=receiving_token,
                taker_amount=receiving_amount,
                taker_address=target_address,
            )
        elif role == 'taker':
            self.raiden_api.expect_token_swap(
                identifier=identifier,
                maker_token=receiving_token,
                maker_amount=receiving_amount,
                maker_address=target_address,
                taker_token=sending_token,
                taker_amount=sending_amount,
                taker_address=self.raiden_api.address
            )
        else:
            # should never happen, role is validated in the schema
            return api_error(
                errors='Provided invalid token swap role {}'.format(role),
                status_code=HTTPStatus.BAD_REQUEST,
            )

        return api_response(result=dict(), status_code=HTTPStatus.CREATED)
Exemplo n.º 6
0
class RestAPI:
    """
    This wraps around the actual RaidenAPI in api/python.
    It will provide the additional, neccessary RESTful logic and
    the proper JSON-encoding of the Objects provided by the RaidenAPI
    """
    version = 1

    def __init__(self, raiden_api):
        self.raiden_api = raiden_api
        self.channel_schema = ChannelStateSchema()
        self.address_list_schema = AddressListSchema()
        self.partner_per_token_list_schema = PartnersPerTokenListSchema()
        self.transfer_schema = TransferSchema()
        #####sqlite_demo
        self.crosstransaction_schema = CrossTransactionSchema()
        self.crosstransaction_sql_schema = Crosstransaction_sql_schema()

    def get_our_address(self):
        return api_response(result=dict(
            our_address=to_checksum_address(self.raiden_api.address)), )

    def register_token(self, registry_address, token_address):
        try:
            token_network_address = self.raiden_api.token_network_register(
                registry_address,
                token_address,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except (InvalidAddress, AlreadyRegisteredTokenAddress,
                TransactionThrew) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        return api_response(
            result=dict(token_network_address=to_checksum_address(
                token_network_address)),
            status_code=HTTPStatus.CREATED,
        )

    def open(
        self,
        registry_address,
        partner_address,
        token_address,
        settle_timeout=None,
        reveal_timeout=None,
        balance=None,
    ):

        try:
            self.raiden_api.channel_open(
                registry_address,
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, DuplicatedChannelError,
                TokenNotRegistered) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if balance:
            # make initial deposit
            try:
                self.raiden_api.set_total_channel_deposit(
                    registry_address,
                    token_address,
                    partner_address,
                    balance,
                )
            except EthNodeCommunicationError:
                return api_response(
                    result='',
                    status_code=HTTPStatus.ACCEPTED,
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED,
                )
            except DepositOverLimit as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.CONFLICT,
                )
            except DepositMismatch as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.CONFLICT,
                )

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(self.raiden_api.raiden),
            registry_address,
            token_address,
            partner_address,
        )

        result = self.channel_schema.dump(channel_state)

        return api_response(
            result=result.data,
            status_code=HTTPStatus.CREATED,
        )

    def connect(
        self,
        registry_address,
        token_address,
        funds,
        initial_channel_target=None,
        joinable_funds_target=None,
    ):

        try:
            self.raiden_api.token_network_connect(
                registry_address,
                token_address,
                funds,
                initial_channel_target,
                joinable_funds_target,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )
        except InvalidAmount as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        return api_response(
            result=dict(),
            status_code=HTTPStatus.NO_CONTENT,
        )

    def leave(self, registry_address, token_address):
        closed_channels = self.raiden_api.token_network_leave(
            registry_address,
            token_address,
        )
        closed_channels = [
            self.channel_schema.dump(channel_state).data
            for channel_state in closed_channels
        ]
        return api_response(result=closed_channels)

    def get_connection_managers_info(self, registry_address):
        """Get a dict whose keys are token addresses and whose values are
        open channels, funds of last request, sum of deposits and number of channels"""
        connection_managers = dict()

        for token in self.raiden_api.get_tokens_list(registry_address):
            token_network_identifier = views.get_token_network_identifier_by_token_address(
                views.state_from_raiden(self.raiden_api.raiden),
                payment_network_id=registry_address,
                token_address=token,
            )

            try:
                connection_manager = self.raiden_api.raiden.connection_manager_for_token_network(
                    token_network_identifier, )
            except InvalidAddress:
                connection_manager = None

            open_channels = views.get_channelstate_open(
                chain_state=views.state_from_raiden(self.raiden_api.raiden),
                payment_network_id=registry_address,
                token_address=token,
            )
            if connection_manager is not None and open_channels:
                connection_managers[to_checksum_address(
                    connection_manager.token_address)] = {
                        'funds':
                        connection_manager.funds,
                        'sum_deposits':
                        views.get_our_capacity_for_token_network(
                            views.state_from_raiden(self.raiden_api.raiden),
                            registry_address,
                            token,
                        ),
                        'channels':
                        len(open_channels),
                    }

        return connection_managers

    def get_channel_list(self,
                         registry_address,
                         token_address=None,
                         partner_address=None):
        raiden_service_result = self.raiden_api.get_channel_list(
            registry_address,
            token_address,
            partner_address,
        )
        assert isinstance(raiden_service_result, list)
        result = [
            self.channel_schema.dump(channel_schema).data
            for channel_schema in raiden_service_result
        ]
        return api_response(result=result)

    def get_tokens_list(self, registry_address):
        raiden_service_result = self.raiden_api.get_tokens_list(
            registry_address)
        assert isinstance(raiden_service_result, list)
        tokens_list = AddressList(raiden_service_result)
        result = self.address_list_schema.dump(tokens_list)
        return api_response(result=result.data)

    def get_network_events(self, registry_address, from_block, to_block):
        try:
            raiden_service_result = self.raiden_api.get_network_events(
                registry_address,
                from_block,
                to_block,
            )
        except InvalidBlockNumberInput as e:
            return api_error(str(e), status_code=HTTPStatus.CONFLICT)

        return api_response(
            result=normalize_events_list(raiden_service_result))

    def get_token_network_events(self, token_address, from_block, to_block):
        try:
            raiden_service_result = self.raiden_api.get_token_network_events(
                token_address,
                from_block,
                to_block,
            )
            return api_response(
                result=normalize_events_list(raiden_service_result))
        except UnknownTokenAddress as e:
            return api_error(str(e), status_code=HTTPStatus.NOT_FOUND)
        except InvalidBlockNumberInput as e:
            return api_error(str(e), status_code=HTTPStatus.CONFLICT)

    def get_channel_events(
        self,
        token_address,
        partner_address=None,
        from_block=None,
        to_block=None,
    ):
        try:
            raiden_service_result = self.raiden_api.get_channel_events(
                token_address,
                partner_address,
                from_block,
                to_block,
            )
        except InvalidBlockNumberInput as e:
            return api_error(str(e), status_code=HTTPStatus.CONFLICT)

        return api_response(
            result=normalize_events_list(raiden_service_result))

    def get_channel(self, registry_address, token_address, partner_address):
        try:
            channel_state = self.raiden_api.get_channel(
                registry_address=registry_address,
                token_address=token_address,
                partner_address=partner_address,
            )
            result = self.channel_schema.dump(channel_state)
            return api_response(result=result.data)
        except ChannelNotFound as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.NOT_FOUND,
            )

    def get_partners_by_token(self, registry_address, token_address):
        return_list = []
        raiden_service_result = self.raiden_api.get_channel_list(
            registry_address,
            token_address,
        )
        for result in raiden_service_result:
            return_list.append({
                'partner_address':
                result.partner_state.address,
                'channel':
                url_for(
                    # TODO: Somehow nicely parameterize this for future versions
                    'v1_resources.channelsresourcebytokenandpartneraddress',
                    token_address=token_address,
                    partner_address=result.partner_state.address,
                ),
            })

        schema_list = PartnersPerTokenList(return_list)
        result = self.partner_per_token_list_schema.dump(schema_list)
        return api_response(result=result.data)

    def initiate_transfer(
        self,
        registry_address,
        token_address,
        target_address,
        amount,
        identifier,
    ):

        if identifier is None:
            identifier = create_default_identifier()

        try:
            transfer_result = self.raiden_api.transfer(
                registry_address=registry_address,
                token_address=token_address,
                target=target_address,
                amount=amount,
                identifier=identifier,
            )
        except (InvalidAmount, InvalidAddress) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if transfer_result is False:
            return api_error(
                errors="Payment couldn't be completed "
                "(insufficient funds, no route to target or target offline).",
                status_code=HTTPStatus.CONFLICT,
            )

        transfer = {
            'initiator_address': self.raiden_api.address,
            'registry_address': registry_address,
            'token_address': token_address,
            'target_address': target_address,
            'amount': amount,
            'identifier': identifier,
        }
        result = self.transfer_schema.dump(transfer)
        return api_response(result=result.data)

    def _deposit(self, registry_address, channel_state, total_deposit):
        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            return api_error(
                errors="Can't set total deposit on a closed channel",
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            self.raiden_api.set_total_channel_deposit(
                registry_address,
                channel_state.token_address,
                channel_state.partner_state.address,
                total_deposit,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )
        except DepositOverLimit as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except DepositMismatch as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        updated_channel_state = self.raiden_api.get_channel(
            registry_address,
            channel_state.token_address,
            channel_state.partner_state.address,
        )

        result = self.channel_schema.dump(updated_channel_state)
        return api_response(result=result.data)

    def _close(self, registry_address, channel_state):
        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            return api_error(
                errors='Attempted to close an already closed channel',
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            self.raiden_api.channel_close(
                registry_address,
                channel_state.token_address,
                channel_state.partner_state.address,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        updated_channel_state = self.raiden_api.get_channel(
            registry_address,
            channel_state.token_address,
            channel_state.partner_state.address,
        )

        result = self.channel_schema.dump(updated_channel_state)
        return api_response(result=result.data)

    def patch_channel(
        self,
        registry_address,
        token_address,
        partner_address,
        total_deposit=None,
        state=None,
    ):
        if total_deposit is not None and state is not None:
            return api_error(
                errors=
                "Can not update a channel's total deposit and state at the same time",
                status_code=HTTPStatus.CONFLICT,
            )

        if total_deposit is None and state is None:
            return api_error(
                errors=
                "Nothing to do. Should either provide 'total_deposit' or 'state' argument",
                status_code=HTTPStatus.BAD_REQUEST,
            )

        try:
            channel_state = self.raiden_api.get_channel(
                registry_address=registry_address,
                token_address=token_address,
                partner_address=partner_address,
            )

        except ChannelNotFound:
            return api_error(
                errors='Requested channel for token {} and partner {} not found'
                .format(
                    to_checksum_address(token_address),
                    to_checksum_address(partner_address),
                ),
                status_code=HTTPStatus.CONFLICT,
            )

        if total_deposit is not None:
            result = self._deposit(registry_address, channel_state,
                                   total_deposit)

        elif state == CHANNEL_STATE_CLOSED:
            result = self._close(registry_address, channel_state)

        else:  # should never happen, channel_state is validated in the schema
            result = api_error(
                errors='Provided invalid channel state {}'.format(state),
                status_code=HTTPStatus.BAD_REQUEST,
            )

        return result

    #demo
    def start_cross(self,
                    registry_address,
                    token_address,
                    target_address,
                    initiator_address,
                    sendETH_amount,
                    sendBTC_amount,
                    receiveBTC_address,
                    cross_type,
                    identifier=None):
        if identifier is None:
            identifier = create_default_identifier()

        try:
            self.raiden_api.crosstransaction_async(
                registry_address, token_address, target_address,
                initiator_address, sendETH_amount, sendBTC_amount,
                receiveBTC_address, cross_type, identifier)
        except Exception as e:
            print(str(e))
            return api_error(
                errors="cross err:" + str(e),
                status_code=HTTPStatus.CONFLICT,
            )

        cross_transfer = {
            'initiator_address': initiator_address,
            'target_address': target_address,
            'token_address': token_address,
            'sendETH_amount': sendETH_amount,
            'sendBTC_amount': sendBTC_amount,
            'cross_type': cross_type,
        }
        result = self.crosstransaction_schema.dump(cross_transfer)
        return api_response(result=result.data)

    #demo
    def get_crosstransaction(self, cross_id):

        result = self.raiden_api.get_crosstransaction_by_id(cross_id)

        crosstransaction = {
            "crossid": result[0],
            "initiator_address": result[1],
            "target_address": result[2],
            "token_network_identifier": result[3],
            'sendETH_amount': result[4],
            'sendBTC_amount': result[5],
            'status': result[7],
        }
        result = self.crosstransaction_sql_schema.dump(crosstransaction)
        return api_response(result=result.data)

    def get_crosstransaction_all(self):

        res = self.raiden_api.get_crosstransaction_all()
        print(res)
        crosstransaction_all = list(dict())
        for result in res:
            crosstransaction = {
                "crossid": result[0],
                "initiator_address": result[1],
                "target_address": result[2],
                "token_network_identifier": result[3],
                'sendETH_amount': result[4],
                'sendBTC_amount': result[5],
                'status': result[7],
            }
            crosstransaction_all.append(crosstransaction)
        print(crosstransaction_all)
        return api_response(result=crosstransaction_all)

    def state_change_by_r(self, hashr):
        return self.raiden_api.get_state_change_by_r(hashr)

    def post_lnd(self, port, identity, address, macaroon):
        return self.raiden_api.post_lnd(port, identity, address, macaroon)

    def get_lnd(self):
        return self.raiden_api.get_lnd()
Exemplo n.º 7
0
class RestAPI:
    """
    This wraps around the actual RaidenAPI in api/python.
    It will provide the additional, neccessary RESTful logic and
    the proper JSON-encoding of the Objects provided by the RaidenAPI
    """
    version = 1

    def __init__(self, raiden_api):
        self.raiden_api = raiden_api
        self.channel_schema = ChannelStateSchema()
        self.address_list_schema = AddressListSchema()
        self.partner_per_token_list_schema = PartnersPerTokenListSchema()
        self.transfer_schema = TransferSchema()

    def get_our_address(self):
        return api_response(
            result=dict(our_address=to_checksum_address(self.raiden_api.address)),
        )

    def register_token(self, registry_address, token_address):
        try:
            token_network_address = self.raiden_api.token_network_register(
                registry_address,
                token_address,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except (InvalidAddress, AlreadyRegisteredTokenAddress, TransactionThrew) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        return api_response(
            result=dict(token_network_address=to_checksum_address(token_network_address)),
            status_code=HTTPStatus.CREATED,
        )

    def open(
            self,
            registry_address,
            partner_address,
            token_address,
            settle_timeout=None,
            reveal_timeout=None,
            balance=None,
    ):

        try:
            self.raiden_api.channel_open(
                registry_address,
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, DuplicatedChannelError) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if balance:
            # make initial deposit
            try:
                self.raiden_api.set_total_channel_deposit(
                    registry_address,
                    token_address,
                    partner_address,
                    balance,
                )
            except EthNodeCommunicationError:
                return api_response(
                    result='',
                    status_code=HTTPStatus.ACCEPTED,
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED,
                )
            except DepositOverLimit as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.EXPECTATION_FAILED,
                )

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(self.raiden_api.raiden),
            registry_address,
            token_address,
            partner_address,
        )

        result = self.channel_schema.dump(channel_state)

        return api_response(
            result=result.data,
            status_code=HTTPStatus.CREATED,
        )

    def connect(
            self,
            registry_address,
            token_address,
            funds,
            initial_channel_target=None,
            joinable_funds_target=None,
    ):

        try:
            self.raiden_api.token_network_connect(
                registry_address,
                token_address,
                funds,
                initial_channel_target,
                joinable_funds_target,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        return api_response(
            result=dict(),
            status_code=HTTPStatus.NO_CONTENT,
        )

    def leave(self, registry_address, token_address, only_receiving):
        closed_channels = self.raiden_api.token_network_leave(
            registry_address,
            token_address,
            only_receiving,
        )
        closed_channels = [
            self.channel_schema.dump(channel_state).data
            for channel_state in closed_channels
        ]
        return api_response(result=closed_channels)

    def get_connection_managers_info(self, registry_address):
        """Get a dict whose keys are token addresses and whose values are
        open channels, funds of last request, sum of deposits and number of channels"""
        connection_managers = dict()

        for token in self.raiden_api.get_tokens_list(registry_address):
            token_network_identifier = views.get_token_network_identifier_by_token_address(
                views.state_from_raiden(self.raiden_api.raiden),
                payment_network_id=registry_address,
                token_address=token,
            )

            try:
                connection_manager = self.raiden_api.raiden.connection_manager_for_token_network(
                    token_network_identifier,
                )
            except InvalidAddress:
                connection_manager = None

            open_channels = views.get_channelstate_open(
                chain_state=views.state_from_raiden(self.raiden_api.raiden),
                payment_network_id=registry_address,
                token_address=token,
            )
            if connection_manager is not None and open_channels:
                connection_managers[to_checksum_address(connection_manager.token_address)] = {
                    'funds': connection_manager.funds,
                    'sum_deposits': views.get_our_capacity_for_token_network(
                        views.state_from_raiden(self.raiden_api.raiden),
                        registry_address,
                        token,
                    ),
                    'channels': len(open_channels),
                }

        return connection_managers

    def get_channel_list(self, registry_address, token_address=None, partner_address=None):
        raiden_service_result = self.raiden_api.get_channel_list(
            registry_address,
            token_address,
            partner_address,
        )
        assert isinstance(raiden_service_result, list)
        result = [
            self.channel_schema.dump(channel_schema).data
            for channel_schema in raiden_service_result
        ]
        return api_response(result=result)

    def get_tokens_list(self, registry_address):
        raiden_service_result = self.raiden_api.get_tokens_list(registry_address)
        assert isinstance(raiden_service_result, list)
        tokens_list = AddressList(raiden_service_result)
        result = self.address_list_schema.dump(tokens_list)
        return api_response(result=result.data)

    def get_network_events(self, registry_address, from_block, to_block):
        try:
            raiden_service_result = self.raiden_api.get_network_events(
                registry_address,
                from_block,
                to_block,
            )
        except InvalidBlockNumberInput as e:
            return api_error(str(e), status_code=HTTPStatus.CONFLICT)

        return api_response(result=normalize_events_list(raiden_service_result))

    def get_token_network_events(self, token_address, from_block, to_block):
        try:
            raiden_service_result = self.raiden_api.get_token_network_events(
                token_address,
                from_block,
                to_block,
            )
            return api_response(result=normalize_events_list(raiden_service_result))
        except UnknownTokenAddress as e:
            return api_error(str(e), status_code=HTTPStatus.NOT_FOUND)
        except InvalidBlockNumberInput as e:
            return api_error(str(e), status_code=HTTPStatus.CONFLICT)

    def get_channel_events(
            self,
            token_address,
            partner_address=None,
            from_block=None,
            to_block=None,
    ):
        try:
            raiden_service_result = self.raiden_api.get_channel_events(
                token_address,
                partner_address,
                from_block,
                to_block,
            )
        except InvalidBlockNumberInput as e:
            return api_error(str(e), status_code=HTTPStatus.CONFLICT)

        return api_response(result=normalize_events_list(raiden_service_result))

    def get_channel(self, registry_address, token_address, partner_address):
        try:
            channel_state = self.raiden_api.get_channel(
                registry_address=registry_address,
                token_address=token_address,
                partner_address=partner_address,
            )
            result = self.channel_schema.dump(channel_state)
            return api_response(result=result.data)
        except ChannelNotFound as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.NOT_FOUND,
            )

    def get_partners_by_token(self, registry_address, token_address):
        return_list = []
        raiden_service_result = self.raiden_api.get_channel_list(
            registry_address,
            token_address,
        )
        for result in raiden_service_result:
            return_list.append({
                'partner_address': result.partner_state.address,
                'channel': url_for(
                    # TODO: Somehow nicely parameterize this for future versions
                    'v1_resources.channelsresourcebytokenandpartneraddress',
                    token_address=token_address,
                    partner_address=result.partner_state.address,
                ),
            })

        schema_list = PartnersPerTokenList(return_list)
        result = self.partner_per_token_list_schema.dump(schema_list)
        return api_response(result=result.data)

    def initiate_transfer(
            self,
            registry_address,
            token_address,
            target_address,
            amount,
            identifier,
    ):

        if identifier is None:
            identifier = create_default_identifier()

        try:
            transfer_result = self.raiden_api.transfer(
                registry_address=registry_address,
                token_address=token_address,
                target=target_address,
                amount=amount,
                identifier=identifier,
            )
        except (InvalidAmount, InvalidAddress) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if transfer_result is False:
            return api_error(
                errors="Payment couldn't be completed "
                "(insufficient funds or no route to target).",
                status_code=HTTPStatus.CONFLICT,
            )

        transfer = {
            'initiator_address': self.raiden_api.address,
            'registry_address': registry_address,
            'token_address': token_address,
            'target_address': target_address,
            'amount': amount,
            'identifier': identifier,
        }
        result = self.transfer_schema.dump(transfer)
        return api_response(result=result.data)

    def _deposit(self, registry_address, channel_state, total_deposit):
        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            return api_error(
                errors="Can't set total deposit on a closed channel",
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            self.raiden_api.set_total_channel_deposit(
                registry_address,
                channel_state.token_address,
                channel_state.partner_state.address,
                total_deposit,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )
        except DepositOverLimit as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.EXPECTATION_FAILED,
            )

        updated_channel_state = self.raiden_api.get_channel(
            registry_address,
            channel_state.token_address,
            channel_state.partner_state.address,
        )

        result = self.channel_schema.dump(updated_channel_state)
        return api_response(result=result.data)

    def _close(self, registry_address, channel_state):
        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            return api_error(
                errors='Attempted to close an already closed channel',
                status_code=HTTPStatus.CONFLICT,
            )

        try:
            self.raiden_api.channel_close(
                registry_address,
                channel_state.token_address,
                channel_state.partner_state.address,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        updated_channel_state = self.raiden_api.get_channel(
            registry_address,
            channel_state.token_address,
            channel_state.partner_state.address,
        )

        result = self.channel_schema.dump(updated_channel_state)
        return api_response(result=result.data)

    def patch_channel(
            self,
            registry_address,
            token_address,
            partner_address,
            total_deposit=None,
            state=None,
    ):
        if total_deposit is not None and state is not None:
            return api_error(
                errors="Can not update a channel's total deposit and state at the same time",
                status_code=HTTPStatus.CONFLICT,
            )

        if total_deposit is None and state is None:
            return api_error(
                errors="Nothing to do. Should either provide 'total_deposit' or 'state' argument",
                status_code=HTTPStatus.BAD_REQUEST,
            )

        try:
            channel_state = self.raiden_api.get_channel(
                registry_address=registry_address,
                token_address=token_address,
                partner_address=partner_address,
            )

        except ChannelNotFound:
            return api_error(
                errors='Requested channel for token {} and partner {} not found'.format(
                    to_checksum_address(token_address),
                    to_checksum_address(partner_address),
                ),
                status_code=HTTPStatus.CONFLICT,
            )

        if total_deposit is not None:
            result = self._deposit(registry_address, channel_state, total_deposit)

        elif state == CHANNEL_STATE_CLOSED:
            result = self._close(registry_address, channel_state)

        else:  # should never happen, channel_state is validated in the schema
            result = api_error(
                errors='Provided invalid channel state {}'.format(state),
                status_code=HTTPStatus.BAD_REQUEST,
            )

        return result
Exemplo n.º 8
0
 def __init__(self, raiden_api):
     self.raiden_api = raiden_api
     self.channel_schema = ChannelStateSchema()
     self.address_list_schema = AddressListSchema()
     self.partner_per_token_list_schema = PartnersPerTokenListSchema()
     self.transfer_schema = TransferSchema()