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
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
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
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
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
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
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