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)
예제 #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)
예제 #4
0
    def revert_attempt_conversion(self, attempt: TransactionAttempt):
        if attempt.currency == "coin":
            cv = self._coin_integer_converter_service
        elif attempt.currency == "waves":
            cv = self._asset_integer_converter_service
        else:
            raise Exception("unknown currency")

        receivers = []

        for i in range(0, len(attempt.receivers)):
            amount = cast(int, attempt.receivers[i].amount)  # type: int

            receivers.append(
                TransactionAttemptReceiver(
                    amount=cv.revert_amount_conversion(amount),
                    address=attempt.receivers[i].address))

        fee = attempt.fee

        if attempt.currency == "coin":
            fee = cv.revert_amount_conversion(cast(int, fee))

        return TransactionAttempt(receivers=receivers,
                                  fee=fee,
                                  sender=attempt.sender,
                                  currency=attempt.currency)
예제 #5
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 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")
            ])
    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()
예제 #8
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))
 def _attempt_from_dict(self, data: dict) -> TransactionAttempt:
     return TransactionAttempt(
         currency=data[TransactionAttempt.DICT_CURRENCY],
         fee=int(data[TransactionAttempt.DICT_FEE]),
         sender=data[TransactionAttempt.DICT_SENDER],
         receivers=map_array(self._receiver_from_dict, data[TransactionAttempt.DICT_RECEIVERS]))