def test_handle_transaction_multi_receiver(self, mock_datetime: MagicMock):
        now = MagicMock()
        mock_datetime.utcnow.return_value = now
        gateway_coin_address = self._gateway_managed_receiver.address
        dst_waves_address = '039769'
        incoming_transaction = Transaction(
            tx='723968', receivers=[self._gateway_managed_receiver])

        amount_after_fees = self._gateway_managed_receiver.amount - self._coin_standard_fee - self._gateway_fee

        attempts = [
            TransactionAttempt(sender=gateway_coin_address,
                               currency="coin",
                               fee=self._coin_standard_fee,
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=self._gateway_address,
                                       amount=amount_after_fees),
                                   TransactionAttemptReceiver(
                                       address=self._gateway_owner_address,
                                       amount=self._gateway_fee)
                               ]),
            TransactionAttempt(sender=self._gateway_waves_address,
                               fee=self._waves_standard_fee,
                               currency="waves",
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=dst_waves_address,
                                       amount=amount_after_fees)
                               ])
        ]

        trigger = AttemptListTrigger(tx=incoming_transaction.tx,
                                     currency="coin",
                                     receiver=0)

        attempt_list = TransactionAttemptList(trigger=trigger,
                                              attempts=attempts,
                                              created_at=now,
                                              last_modified=now)

        self._attempt_list_storage.find_by_trigger.return_value = None
        self._map_storage.get_waves_address_by_coin_address.return_value = dst_waves_address

        self._coin_transaction_consumer_impl.handle_transaction(
            incoming_transaction)

        self._attempt_list_storage.find_by_trigger.assert_any_call(
            AttemptListTrigger(tx=incoming_transaction.tx,
                               receiver=0,
                               currency="coin"))
        self._map_storage.get_waves_address_by_coin_address.assert_called_once_with(
            gateway_coin_address)
        self._attempt_service.continue_transaction_attempt_list.assert_not_called(
        )
        self._attempt_list_storage.safely_save_attempt_list.assert_called_once_with(
            attempt_list)
    def test_handle_receiver(self, mock_datetime: MagicMock):
        now = MagicMock()
        mock_datetime.utcnow.return_value = now

        coin_receiver = "82396457"
        amount_after_fees = self._gateway_waves_receiver.amount - 2 * self._coin_standard_fee - self._gateway_fee
        tx = "78265"
        self._coin_address_validation_service.validate_address.return_value = True

        attempts = [
            TransactionAttempt(sender=self._gateway_coin_address_secret.public,
                               fee=self._coin_standard_fee,
                               currency="coin",
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=coin_receiver,
                                       amount=amount_after_fees)
                               ]),
            TransactionAttempt(sender=self._gateway_coin_address_secret.public,
                               fee=self._coin_standard_fee,
                               currency="coin",
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=self._gateway_owner_address,
                                       amount=self._gateway_fee)
                               ])
        ]

        trigger = AttemptListTrigger(tx=tx, currency="waves", receiver=0)

        self._attempt_list_storage.find_by_trigger.return_value = None
        attempt_list = TransactionAttemptList(trigger=trigger,
                                              attempts=attempts,
                                              created_at=now,
                                              last_modified=now)

        self._waves_chain_query_service.get_coin_receiver_address_from_transaction.return_value = coin_receiver

        self._waves_transaction_consumer_impl._handle_receiver(
            tx, self._gateway_waves_receiver, 0)

        self._waves_chain_query_service.get_coin_receiver_address_from_transaction.assert_called_once_with(
            tx)
        self._attempt_service.continue_transaction_attempt_list.assert_not_called(
        )
        self._attempt_list_storage.find_by_trigger.assert_called_once_with(
            AttemptListTrigger(tx=tx, currency="waves", receiver=0))
        self._attempt_list_storage.safely_save_attempt_list.assert_called_once_with(
            attempt_list)
Example #3
0
    def test_update_attempt_list(self):
        trigger = AttemptListTrigger(
            tx="792873", receiver=1, currency="waves", senders=[TransactionSender(address="723789")])

        attempt_list = TransactionAttemptList(
            trigger=trigger,
            attempts=[
                TransactionAttempt(
                    currency="coin",
                    fee=100,
                    receivers=[TransactionAttemptReceiver(address="973846", amount=234)],
                    sender="739264857")
            ])

        expected_query = dict()
        expected_query[TransactionAttemptList.DICT_ID] = attempt_list.attempt_list_id
        mock_find_one_result = MagicMock()
        mock_attempt_list_as_dict_result = MagicMock()

        self._collection.find_one_and_replace.return_value = mock_find_one_result
        self._serializer.attempt_list_as_dict.return_value = mock_attempt_list_as_dict_result

        self._storage.update_attempt_list(attempt_list)

        self._collection.find_one_and_replace.assert_called_once_with(expected_query, mock_attempt_list_as_dict_result)
        self._serializer.attempt_list_as_dict.assert_called_once_with(attempt_list)
    def _trigger_from_dict(self, data: dict) -> AttemptListTrigger:
        if AttemptListTrigger.DICT_SENDERS_KEY in data:
            senders = map_array(self._sender_from_dict, data[AttemptListTrigger.DICT_SENDERS_KEY])
        else:
            senders = None

        return AttemptListTrigger(
            tx=data[AttemptListTrigger.DICT_TX],
            receiver=data[AttemptListTrigger.DICT_RECEIVER],
            currency=data[AttemptListTrigger.DICT_CURRENCY],
            senders=senders)
Example #5
0
    def test_get_attempt_list_by_trigger(self):
        mock_find_by_trigger_result = MagicMock()
        mock_trigger = AttemptListTrigger(tx="2396487",
                                          receiver=3,
                                          currency="coin")
        self._attempt_list_storage.find_by_trigger.return_value = mock_find_by_trigger_result

        res = self._gateway_controller.get_attempt_list_by_trigger(
            mock_trigger)

        self.assertEqual(res, mock_find_by_trigger_result)
        self._attempt_list_storage.find_by_trigger.assert_called_once_with(
            mock_trigger)
Example #6
0
    def test_find_by_trigger_senders_is_none_not_found(self):
        trigger = AttemptListTrigger(tx="72935687", receiver=3, currency="2793658", senders=None)
        expected_query = dict()
        expected_query[TransactionAttemptList.DICT_TRIGGER + "." + AttemptListTrigger.DICT_RECEIVER] = trigger.receiver
        expected_query[TransactionAttemptList.DICT_TRIGGER + "." + AttemptListTrigger.DICT_CURRENCY] = trigger.currency
        expected_query[TransactionAttemptList.DICT_TRIGGER + "." + AttemptListTrigger.DICT_TX] = trigger.tx

        self._collection.find_one.return_value = None

        res = self._storage.find_by_trigger(trigger)

        self.assertIsNone(res)
        self._collection.find_one.assert_called_once_with(expected_query)
        self._serializer.attempt_list_from_dict.assert_not_called()
Example #7
0
    def _filter_receivers(self, transaction: Transaction) -> List[int]:
        res = list()

        for i in range(0, len(transaction.receivers)):
            if self._gateway_pywaves_address.address == transaction.receivers[
                    i].address:
                attempt_list = self._attempt_list_storage.find_by_trigger(
                    AttemptListTrigger(tx=transaction.tx,
                                       currency="waves",
                                       receiver=i))

                if attempt_list is None or not attempt_list.is_complete():
                    res.append(i)

        return res
Example #8
0
    def test_revert_attempt_list_conversion_waves(self):
        """Ensures that the fee is not converted when using the asset_integer_converter_service."""
        trigger = AttemptListTrigger(
            tx="792873",
            receiver=1,
            currency="coin",
            senders=[TransactionSender(address="723789")])

        attempt_list = TransactionAttemptList(
            trigger=trigger,
            attempts=[
                TransactionAttempt(
                    currency="waves",
                    fee=100,
                    receivers=[
                        TransactionAttemptReceiver(address="973846",
                                                   amount=234),
                        TransactionAttemptReceiver(address="9327468",
                                                   amount=235)
                    ],
                    sender="739264857")
            ])

        expected_attempt_list = TransactionAttemptList(
            trigger=trigger,
            attempts=[
                TransactionAttempt(
                    currency="waves",
                    fee=100,
                    receivers=[
                        TransactionAttemptReceiver(address="973846",
                                                   amount=0.234),
                        TransactionAttemptReceiver(address="9327468",
                                                   amount=0.235)
                    ],
                    sender="739264857")
            ])

        def mock_converter(value: Any):
            return value / 1000

        self._asset_integer_converter_service.revert_amount_conversion.side_effect = mock_converter

        res = self._attempt_list_converter.revert_attempt_list_conversion(
            attempt_list)

        self.assertEqual(res, expected_attempt_list)
 def test_filter_transaction_by_receivers_success(self):
     """
     The filter should pass a transaction that has not yet been processed and
     contains a gateway managed address
     """
     self._attempt_list_storage.gateway_transaction_exists.return_value = False
     self._map_storage.coin_address_exists.return_value = True
     self._attempt_list_storage.find_by_trigger.return_value = None
     transaction = Transaction(tx='723968',
                               receivers=[self._gateway_managed_receiver])
     res = self._coin_transaction_consumer_impl.filter_transaction(
         transaction)
     self.assertTrue(res)
     self._map_storage.coin_address_exists.assert_called_once_with(
         self._gateway_managed_receiver.address)
     self._attempt_list_storage.find_by_trigger.assert_called_once_with(
         AttemptListTrigger(tx=transaction.tx, receiver=0, currency="coin"))
    def test_get_attempt_list_by_trigger(self):
        mock_trigger = AttemptListTrigger(tx="2937468",
                                          currency="coin",
                                          receiver=0)
        mock_attempt_list = MagicMock()
        mock_converter_result = MagicMock()

        self._gateway_controller.get_attempt_list_by_trigger.return_value = mock_attempt_list
        self._converter.revert_attempt_list_conversion.return_value = mock_converter_result

        res = self._proxy.get_attempt_list_by_trigger(mock_trigger)

        self._converter.revert_attempt_list_conversion.assert_called_once_with(
            mock_attempt_list)
        self._gateway_controller.get_attempt_list_by_trigger.assert_called_once_with(
            mock_trigger)
        self.assertEqual(res, mock_converter_result)
    def setUp(self):
        self._attempt_list_serializer = TransactionAttemptListSerializer()

        trigger = AttemptListTrigger(
            tx="792873", receiver=1, currency="waves", senders=[TransactionSender(address="723789")])

        self._attempt_list = TransactionAttemptList(
            trigger=trigger,
            attempts=[
                TransactionAttempt(
                    currency="coin",
                    fee=100,
                    receivers=[
                        TransactionAttemptReceiver(address="973846", amount=234),
                        TransactionAttemptReceiver(address="9327468", amount=235)
                    ],
                    sender="739264857")
            ])
Example #12
0
    def _filter_receivers(self, transaction: Transaction) -> List[int]:
        """
        Filters a given list of transaction receivers for those ones that are gateway managed, but not the
        main gateway coin holder. Those shall be further processed.
        """
        res = list()

        for i in range(0, len(transaction.receivers)):
            address = transaction.receivers[i].address

            if self._is_gateway_managed_coin_address(address) and not self._is_gateway_coin_holder(address):
                attempt_list = self._attempt_list_storage.find_by_trigger(
                    AttemptListTrigger(tx=transaction.tx, currency="coin", receiver=i))

                if attempt_list is None or not attempt_list.is_complete():
                    res.append(i)

        return res
Example #13
0
    def test_continue_transaction_attempt_list(self, mock_datetime: MagicMock):
        now = MagicMock()
        mock_datetime.utcnow.return_value = now

        trigger = AttemptListTrigger(
            tx="792873", receiver=1, currency="waves", senders=[TransactionSender(address="723789")])

        attempt_list = TransactionAttemptList(
            trigger=trigger,
            attempts=[
                TransactionAttempt(
                    currency="coin",
                    fee=100,
                    receivers=[TransactionAttemptReceiver(address="973846", amount=234)],
                    sender="739264857")
            ],
            created_at=now,
            last_modified=now)

        expected_attempt_list = TransactionAttemptList(
            trigger=trigger,
            attempts=[
                TransactionAttempt(
                    currency="coin",
                    fee=100,
                    receivers=[TransactionAttemptReceiver(address="973846", amount=234)],
                    sender="739264857"),
            ],
            transactions=["97238"],
            created_at=now,
            last_modified=now)

        mock_transaction = Transaction(tx="97238", receivers=[TransactionReceiver(address="973846", amount=234)])

        mock_secret = "9723684"

        self._secret_service.get_secret_by_address.return_value = mock_secret
        self._transaction_service.send_coin.return_value = mock_transaction

        self._attempt_list_service.continue_transaction_attempt_list(attempt_list)

        self._storage.update_attempt_list.assert_called_once_with(expected_attempt_list)
        self._transaction_service.send_coin.assert_called_once_with(attempt_list.attempts[0], mock_secret)
        self._secret_service.get_secret_by_address("coin", "739264857")
    def test_handle_receiver_invalid_address(self):
        coin_receiver = "82396457"
        amount_after_fees = self._gateway_waves_receiver.amount - self._coin_standard_fee - self._gateway_fee
        tx = "78265"
        self._coin_address_validation_service.validate_address.return_value = False

        attempts = [
            TransactionAttempt(sender=self._gateway_coin_address_secret.public,
                               fee=self._coin_standard_fee,
                               currency="coin",
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=coin_receiver,
                                       amount=amount_after_fees),
                                   TransactionAttemptReceiver(
                                       address=self._gateway_owner_address,
                                       amount=self._gateway_fee)
                               ])
        ]

        trigger = AttemptListTrigger(tx=tx, currency="waves", receiver=0)

        self._attempt_list_storage.find_by_trigger.return_value = None

        self._waves_chain_query_service.get_coin_receiver_address_from_transaction.return_value = coin_receiver

        self._waves_transaction_consumer_impl._handle_receiver(
            tx, self._gateway_waves_receiver, 0)

        self._waves_chain_query_service.get_coin_receiver_address_from_transaction.assert_called_once_with(
            tx)
        self._coin_address_validation_service.validate_address.assert_called_once_with(
            coin_receiver)
        self._attempt_service.continue_transaction_attempt_list.assert_not_called(
        )
        self._attempt_list_storage.find_by_trigger.assert_not_called()
Example #15
0
    def _handle_receiver(self,
                         tx: str,
                         receiver: TransactionReceiver,
                         index: int,
                         senders: List[TransactionSender] = None) -> None:

        # ---------- Pre-Calculation ----------

        # fee to be used for the custom currency
        coin_fee = cast(int, self._fee_service.get_coin_fee())

        # fee to be transferred to the Gateway owner
        gateway_fee = cast(int, self._fee_service.get_gateway_fee())

        received_amount = cast(int, receiver.amount)

        # the amount of coins to be transferred after applying the fees
        if self._only_one_transaction_receiver:
            amount_after_fees = received_amount - 2 * coin_fee - gateway_fee
        else:
            amount_after_fees = received_amount - coin_fee - gateway_fee

        # receiver coin address
        coin_receiver = self._waves_chain_query_service.get_coin_receiver_address_from_transaction(
            tx)

        # ---------- Pre-Check ----------

        if not self._coin_address_validation_service.validate_address(
                coin_receiver):
            self._logger.warning(
                "Received transaction %s with an invalid coin receiver address %s. "
                "Will be skipped.", tx, coin_receiver)
            return

        if self._gateway_coin_holder_secret.public == coin_receiver:
            self._logger.warning(
                "Received transaction %s with the address of the Gateway coin holder."
                "Will be skipped as an transaction to itself has no effect.",
                tx)
            return

        # transaction must have at least a specific amount to be processed
        if amount_after_fees < 0:
            self._logger.warning(
                "Received transaction %s with an amount of %s, but it is less than the at least "
                "required amount. Will be skipped.", tx, receiver.amount)
            return

        attempt_list = self._attempt_list_storage.find_by_trigger(
            AttemptListTrigger(tx=tx, currency="waves", receiver=index))

        if attempt_list is None:
            trigger = AttemptListTrigger(tx=tx,
                                         receiver=index,
                                         currency="waves",
                                         senders=senders)

            attempts = list()

            if self._only_one_transaction_receiver:
                attempts.append(
                    TransactionAttempt(
                        sender=self._gateway_coin_holder_secret.public,
                        fee=coin_fee,
                        currency="coin",
                        receivers=[
                            TransactionAttemptReceiver(
                                address=self._gateway_owner_address,
                                amount=gateway_fee)
                        ]))

                attempts.append(
                    TransactionAttempt(
                        sender=self._gateway_coin_holder_secret.public,
                        fee=coin_fee,
                        currency="coin",
                        receivers=[
                            TransactionAttemptReceiver(
                                address=coin_receiver,
                                amount=amount_after_fees)
                        ]))
            else:
                attempts.append(
                    TransactionAttempt(
                        sender=self._gateway_coin_holder_secret.public,
                        fee=coin_fee,
                        currency="coin",
                        receivers=[
                            TransactionAttemptReceiver(
                                address=coin_receiver,
                                amount=amount_after_fees),
                            TransactionAttemptReceiver(
                                address=self._gateway_owner_address,
                                amount=gateway_fee)
                        ]))

            attempt_list = TransactionAttemptList(
                trigger,
                attempts,
                last_modified=datetime.datetime.utcnow(),
                created_at=datetime.datetime.utcnow())

            self._attempt_list_storage.safely_save_attempt_list(attempt_list)
            self._logger.info('Created new attempt list %s',
                              str(attempt_list.attempt_list_id))
    def _handle_transaction_receiver(self,
                                     tx: str,
                                     receiver: TransactionReceiver,
                                     index: int,
                                     senders: List[TransactionSender] = None):

        # ---------- Pre-Calculation ----------

        # the gateway address that coins were transferred to
        gateway_managed_address = receiver.address

        # the custom currency fee to be used
        coin_fee = cast(int, self._fee_service.get_coin_fee())

        # the waves fee to be used; not used in the calculation
        waves_fee = cast(int, self._fee_service.get_waves_fee())

        # the fee for the gateway owner; service costs
        gateway_fee = cast(int, self._fee_service.get_gateway_fee())

        # the amount of coins that were received by this receiver
        received_amount = cast(int, receiver.amount)

        # the waves address to receive the amount of coins
        receiver_waves_address = self._map_storage.get_waves_address_by_coin_address(
            gateway_managed_address)

        # the amount of coins to be transferred after applying the fees
        if self._only_one_transaction_receiver:
            amount_after_fees = received_amount - 2 * coin_fee - gateway_fee
        else:
            amount_after_fees = received_amount - coin_fee - gateway_fee

        # ---------- Pre-Check ----------

        # transaction must have minimum amount to be handled
        if amount_after_fees <= 0:
            self._logger.warn(
                "Received transaction %s with an amount of %s, but it is less than the at least "
                "required amount. Will be skipped, but marked as processed.",
                tx, receiver.amount)
            return

        # no mapping was found for some reason; this in an internal error as this should
        # already be prevented by the filter method
        if receiver_waves_address is None:
            raise MappingNotFoundForCoinAddress(gateway_managed_address)

        attempt_list = self._attempt_list_storage.find_by_trigger(
            AttemptListTrigger(tx=tx, currency="coin", receiver=index))

        if attempt_list is None:

            attempts = list()

            if self._only_one_transaction_receiver:
                attempts.append(
                    TransactionAttempt(
                        sender=gateway_managed_address,
                        currency="coin",
                        fee=coin_fee,
                        receivers=[
                            TransactionAttemptReceiver(
                                address=self._gateway_coin_address,
                                amount=amount_after_fees),
                        ]))

                attempts.append(
                    TransactionAttempt(
                        sender=gateway_managed_address,
                        currency="coin",
                        fee=coin_fee,
                        receivers=[
                            TransactionAttemptReceiver(
                                address=self._gateway_owner_address,
                                amount=gateway_fee)
                        ]))
            else:
                attempts.append(
                    TransactionAttempt(
                        sender=gateway_managed_address,
                        currency="coin",
                        fee=coin_fee,
                        receivers=[
                            TransactionAttemptReceiver(
                                address=self._gateway_coin_address,
                                amount=amount_after_fees),
                            TransactionAttemptReceiver(
                                address=self._gateway_owner_address,
                                amount=gateway_fee)
                        ]))

            attempts.append(
                TransactionAttempt(
                    sender=self._gateway_pywaves_address.address,
                    fee=waves_fee,
                    currency="waves",
                    receivers=[
                        TransactionAttemptReceiver(
                            address=receiver_waves_address,
                            amount=amount_after_fees)
                    ]))

            trigger = AttemptListTrigger(tx, index, "coin", senders=senders)
            attempt_list = TransactionAttemptList(
                trigger,
                attempts,
                last_modified=datetime.datetime.utcnow(),
                created_at=datetime.datetime.utcnow())
            self._attempt_list_storage.safely_save_attempt_list(attempt_list)
            self._logger.info('Created new attempt list %s',
                              str(attempt_list.attempt_list_id))