Пример #1
0
    def _is_acceptable_tx(self, tx_message: TransactionMessage) -> bool:
        """
        Check if the tx is acceptable.

        :param tx_message: the transaction message
        :return: whether the transaction is acceptable or not
        """
        if tx_message.get("ledger_id") is not None:
            amount = cast(int, tx_message.get("amount"))
            counterparty_tx_fee = cast(int,
                                       tx_message.get("counterparty_tx_fee"))
            sender_tx_fee = cast(int, tx_message.get("sender_tx_fee"))
            # adjust payment amount to reflect transaction fee split
            amount -= counterparty_tx_fee
            tx_fee = counterparty_tx_fee + sender_tx_fee
            payable = amount + tx_fee
            is_correct_format = isinstance(payable, int)
            crypto_object = self._wallet.crypto_objects.get(
                tx_message.get("ledger_id"))
            balance = self.ledger_apis.token_balance(
                crypto_object.identifier, cast(str, crypto_object.address))
            is_affordable = payable <= balance
            # TODO check against preferences and other constraints
            is_acceptable = is_correct_format and is_affordable
        else:
            is_acceptable = self.preferences.get_score_diff_from_transaction(
                self.ownership_state, tx_message) >= 0.0
        return is_acceptable
Пример #2
0
    def _settle_tx(self, tx_message: TransactionMessage) -> Optional[str]:
        """
        Settle the tx.

        :param tx_message: the transaction message
        :return: the transaction digest
        """
        if tx_message.ledger_id == OFF_CHAIN:
            logger.info(
                "[{}]: Cannot settle transaction, settlement happens off chain!".format(
                    self._agent_name
                )
            )
            tx_digest = OFF_CHAIN_SETTLEMENT_DIGEST
        else:
            logger.info("[{}]: Settling transaction on chain!".format(self._agent_name))
            crypto_object = self.wallet.crypto_objects.get(tx_message.ledger_id)
            tx_digest = self.ledger_apis.transfer(
                crypto_object,
                tx_message.tx_counterparty_addr,
                tx_message.counterparty_amount,
                tx_message.fees,
                info=tx_message.info,
                tx_nonce=cast(str, tx_message.get("tx_nonce")),
            )
        return tx_digest
Пример #3
0
    def _settle_tx(self, tx_message: TransactionMessage) -> Optional[str]:
        """
        Settle the tx.

        :param tx_message: the transaction message
        :return: the transaction digest
        """
        logger.info("[{}]: Settling transaction!".format(self._agent_name))
        if tx_message.get("ledger_id") is not None:
            amount = cast(int, tx_message.get("amount"))
            counterparty_tx_fee = cast(int,
                                       tx_message.get("counterparty_tx_fee"))
            sender_tx_fee = cast(int, tx_message.get("sender_tx_fee"))
            counterparty_address = cast(str, tx_message.get("counterparty"))
            # adjust payment amount to reflect transaction fee split
            amount -= counterparty_tx_fee
            tx_fee = counterparty_tx_fee + sender_tx_fee
            crypto_object = self._wallet.crypto_objects.get(
                tx_message.get("ledger_id"))
            tx_digest = self.ledger_apis.transfer(crypto_object.identifier,
                                                  crypto_object,
                                                  counterparty_address, amount,
                                                  tx_fee)
        else:
            tx_digest = cast(str, tx_message.get("transaction_id"))
        return tx_digest
Пример #4
0
    def check_transaction_is_consistent(
            self, tx_message: TransactionMessage) -> bool:
        """
        Check if the transaction is consistent.

        E.g. check that the agent state has enough money if it is a buyer
        or enough holdings if it is a seller.
        :return: True if the transaction is legal wrt the current state, false otherwise.
        """
        currency_pbk = cast(str, tx_message.get("currency_pbk"))
        if tx_message.get("is_sender_buyer"):
            # check if we have the money to cover amount and tx fee.
            result = self.amount_by_currency[currency_pbk] >= cast(
                int, tx_message.get("amount")) + cast(
                    int, tx_message.get("sender_tx_fee"))
        else:
            # check if we have the goods.
            result = True
            quantities_by_good_pbk = cast(
                Dict[str, int], tx_message.get("quantities_by_good_pbk"))
            for good_pbk, quantity in quantities_by_good_pbk.items():
                result = result and (self.quantities_by_good_pbk[good_pbk] >=
                                     quantity)
            # check if we have the money to cover tx fee.
            result = self.amount_by_currency[currency_pbk] + cast(
                int, tx_message.get("amount")) >= cast(
                    int, tx_message.get("sender_tx_fee"))
        return result
Пример #5
0
    def pop_locked_tx(
            self, transaction_msg: TransactionMessage) -> TransactionMessage:
        """
        Remove a lock (in the form of a transaction).

        :param transaction_msg: the transaction message
        :raise AssertionError: if the transaction with the given transaction id has not been found.

        :return: the transaction
        """
        transaction_id = cast(TransactionId,
                              transaction_msg.get("transaction_id"))
        assert transaction_id in self._locked_txs
        transaction_msg = self._locked_txs.pop(transaction_id)
        self._locked_txs_as_buyer.pop(transaction_id, None)
        self._locked_txs_as_seller.pop(transaction_id, None)
        return transaction_msg
Пример #6
0
    def add_locked_tx(self, transaction_msg: TransactionMessage,
                      as_seller: bool) -> None:
        """
        Add a lock (in the form of a transaction).

        :param transaction_msg: the transaction message
        :param as_seller: whether the agent is a seller or not
        :raise AssertionError: if the transaction is already present.

        :return: None
        """
        transaction_id = cast(TransactionId,
                              transaction_msg.get("transaction_id"))
        assert transaction_id not in self._locked_txs
        self._register_transaction_with_time(transaction_id)
        self._locked_txs[transaction_id] = transaction_msg
        if as_seller:
            self._locked_txs_as_seller[transaction_id] = transaction_msg
        else:
            self._locked_txs_as_buyer[transaction_id] = transaction_msg
Пример #7
0
    def update(self, tx_message: TransactionMessage) -> None:
        """
        Update the agent state from a transaction.

        :param tx: the transaction.
        :param tx_fee: the transaction fee.
        :return: None
        """
        currency_pbk = tx_message.get("currency")
        currency_pbk = cast(str, currency_pbk)
        if tx_message.get("is_sender_buyer"):
            diff = cast(float, tx_message.get("amount")) + cast(float, tx_message.get("sender_tx_fee"))
            self._currency_holdings[currency_pbk] -= diff
        else:
            diff = cast(float, tx_message.get("amount")) - cast(float, tx_message.get("sender_tx_fee"))
            self._currency_holdings[currency_pbk] += diff

        quantities_by_good_pbk = tx_message.get("quantities_by_good_pbk")
        quantities_by_good_pbk = cast(Dict[str, int], quantities_by_good_pbk)
        for good_pbk, quantity in quantities_by_good_pbk.items():
            quantity_delta = quantity if tx_message.get("is_sender_buyer") else -quantity
            self._good_holdings[good_pbk] += quantity_delta