|
|
@ -202,6 +202,84 @@ class Transactions(util.Base):
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_bank_sender(self, platform, platform_buyer, bank_sender):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Add the bank senders into Redis.
|
|
|
|
|
|
|
|
:param platform: name of the platform - freeform
|
|
|
|
|
|
|
|
:param platform_buyer: the username of the buyer on the platform
|
|
|
|
|
|
|
|
:param bank_sender: the sender name from the bank
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
key = f"namemap.{platform}.{platform_buyer}"
|
|
|
|
|
|
|
|
r.sadd(key, bank_sender)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_previous_senders(self, platform, platform_buyer):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Get all the previous bank sender names for the given buyer on the platform.
|
|
|
|
|
|
|
|
:param platform: name of the platform - freeform
|
|
|
|
|
|
|
|
:param platform_buyer: the username of the buyer on the platform
|
|
|
|
|
|
|
|
:return: set of previous buyers
|
|
|
|
|
|
|
|
:rtype: set
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
key = f"namemap.{platform}.{platform_buyer}"
|
|
|
|
|
|
|
|
senders = r.smembers(key)
|
|
|
|
|
|
|
|
senders = util.convert(senders)
|
|
|
|
|
|
|
|
return senders
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def check_valid_sender(self, reference, platform, bank_sender, platform_buyer):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Check that either:
|
|
|
|
|
|
|
|
* The platform buyer has never had a recognised transaction before
|
|
|
|
|
|
|
|
* The bank sender name matches a previous transaction from the platform buyer
|
|
|
|
|
|
|
|
:param reference: the trade reference
|
|
|
|
|
|
|
|
:param platform: name of the platform - freeform
|
|
|
|
|
|
|
|
:param bank_sender: the sender of the bank transaction
|
|
|
|
|
|
|
|
:param platform_buyer: the username of the buyer on the platform
|
|
|
|
|
|
|
|
:return: whether the sender is valid
|
|
|
|
|
|
|
|
:rtype: bool
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
senders = self.get_previous_senders(platform, platform_buyer)
|
|
|
|
|
|
|
|
if platform_buyer in senders:
|
|
|
|
|
|
|
|
print("Platform buyer is in senders!")
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
print("Platform buyer is not in senders")
|
|
|
|
|
|
|
|
self.ux.notify.notify_sender_name_mismatch(reference, platform_buyer, bank_sender)
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def check_tx_sender(self, tx, reference):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Check whether the sender of a given transaction is authorised based on the previous
|
|
|
|
|
|
|
|
transactions of the username that originated the trade reference.
|
|
|
|
|
|
|
|
:param tx: the transaction ID
|
|
|
|
|
|
|
|
:param reference: the trade reference
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
stored_trade = self.get_ref(reference)
|
|
|
|
|
|
|
|
if not stored_trade:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
stored_tx = self.get_tx(tx)
|
|
|
|
|
|
|
|
if not stored_tx:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
bank_sender = stored_tx["sender"]
|
|
|
|
|
|
|
|
platform_buyer = stored_trade["buyer"]
|
|
|
|
|
|
|
|
platform = stored_trade["subclass"]
|
|
|
|
|
|
|
|
is_allowed = self.check_valid_sender(reference, platform, bank_sender, platform_buyer)
|
|
|
|
|
|
|
|
if is_allowed is True:
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_trade_tx(self, reference, txid):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Update a trade to point to a given transaction ID.
|
|
|
|
|
|
|
|
Return False if the trade already has a mapped transaction.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
existing_tx = r.hget(f"trade.{reference}", "tx")
|
|
|
|
|
|
|
|
if existing_tx is None:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
elif existing_tx == "":
|
|
|
|
|
|
|
|
r.hset(f"trade.{reference}", "tx", txid)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
else: # Already a mapped transaction
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def transaction(self, data):
|
|
|
|
def transaction(self, data):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Store details of transaction and post notifications to IRC.
|
|
|
|
Store details of transaction and post notifications to IRC.
|
|
|
@ -223,7 +301,6 @@ class Transactions(util.Base):
|
|
|
|
|
|
|
|
|
|
|
|
subclass = data["subclass"]
|
|
|
|
subclass = data["subclass"]
|
|
|
|
to_store = {
|
|
|
|
to_store = {
|
|
|
|
"trade_id": "",
|
|
|
|
|
|
|
|
"subclass": subclass,
|
|
|
|
"subclass": subclass,
|
|
|
|
"ts": ts,
|
|
|
|
"ts": ts,
|
|
|
|
"txid": txid,
|
|
|
|
"txid": txid,
|
|
|
@ -232,8 +309,10 @@ class Transactions(util.Base):
|
|
|
|
"currency": currency,
|
|
|
|
"currency": currency,
|
|
|
|
"sender": sender,
|
|
|
|
"sender": sender,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r.hmset(f"tx.{txid}", to_store)
|
|
|
|
|
|
|
|
|
|
|
|
self.log.info(f"Transaction processed: {dumps(to_store, indent=2)}")
|
|
|
|
self.log.info(f"Transaction processed: {dumps(to_store, indent=2)}")
|
|
|
|
self.irc.sendmsg(f"AUTO Incoming transaction on {subclass}: {amount}{currency} ({reference})")
|
|
|
|
self.irc.sendmsg(f"AUTO Incoming transaction on {subclass}: {txid} {amount}{currency} ({reference})")
|
|
|
|
|
|
|
|
|
|
|
|
stored_trade_reference = self.reference_partial_check(reference, txid, currency, amount)
|
|
|
|
stored_trade_reference = self.reference_partial_check(reference, txid, currency, amount)
|
|
|
|
if stored_trade_reference is False: # can be None though
|
|
|
|
if stored_trade_reference is False: # can be None though
|
|
|
@ -274,8 +353,13 @@ class Transactions(util.Base):
|
|
|
|
return
|
|
|
|
return
|
|
|
|
if not self.alt_amount_check(amount, currency, reference, stored_trade):
|
|
|
|
if not self.alt_amount_check(amount, currency, reference, stored_trade):
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
platform = stored_trade["subclass"]
|
|
|
|
|
|
|
|
platform_buyer = stored_trade["buyer"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Check sender - we don't do anything with this yet
|
|
|
|
|
|
|
|
sender_valid = self.check_valid_sender(reference, platform, sender, platform_buyer)
|
|
|
|
|
|
|
|
print("Sender valid for trade: ", sender_valid)
|
|
|
|
|
|
|
|
|
|
|
|
r.hmset(f"tx.{txid}", to_store)
|
|
|
|
|
|
|
|
self.release_funds(stored_trade["id"], stored_trade["reference"])
|
|
|
|
self.release_funds(stored_trade["id"], stored_trade["reference"])
|
|
|
|
self.ux.notify.notify_complete_trade(amount, currency)
|
|
|
|
self.ux.notify.notify_complete_trade(amount, currency)
|
|
|
|
|
|
|
|
|
|
|
@ -298,7 +382,33 @@ class Transactions(util.Base):
|
|
|
|
# message_long = rtrn["response"]["data"]["message"]
|
|
|
|
# message_long = rtrn["response"]["data"]["message"]
|
|
|
|
self.irc.sendmsg(f"{dumps(message)}")
|
|
|
|
self.irc.sendmsg(f"{dumps(message)}")
|
|
|
|
|
|
|
|
|
|
|
|
def new_trade(self, asset, trade_id, buyer, currency, amount, amount_crypto, provider):
|
|
|
|
def release_map_trade(self, reference, tx):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Map a trade to a transaction and release if no other TX is
|
|
|
|
|
|
|
|
mapped to the same trade.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
stored_trade = self.get_ref(reference)
|
|
|
|
|
|
|
|
if not stored_trade:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
tx_obj = self.get_tx(tx)
|
|
|
|
|
|
|
|
if not tx_obj:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
platform = stored_trade["subclass"]
|
|
|
|
|
|
|
|
platform_buyer = stored_trade["buyer"]
|
|
|
|
|
|
|
|
bank_sender = tx_obj["sender"]
|
|
|
|
|
|
|
|
trade_id = stored_trade["id"]
|
|
|
|
|
|
|
|
is_updated = self.update_trade_tx(reference, tx)
|
|
|
|
|
|
|
|
if is_updated is None:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
elif is_updated is True:
|
|
|
|
|
|
|
|
# We mapped the trade successfully
|
|
|
|
|
|
|
|
self.release_funds(trade_id, reference)
|
|
|
|
|
|
|
|
print("Adding mapped bank sender", platform_buyer, bank_sender)
|
|
|
|
|
|
|
|
self.add_bank_sender(platform, platform_buyer, bank_sender)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def new_trade(self, subclass, asset, trade_id, buyer, currency, amount, amount_crypto, provider):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Called when we have a new trade in Agora.
|
|
|
|
Called when we have a new trade in Agora.
|
|
|
|
Store details in Redis, generate a reference and optionally let the customer know the reference.
|
|
|
|
Store details in Redis, generate a reference and optionally let the customer know the reference.
|
|
|
@ -310,6 +420,7 @@ class Transactions(util.Base):
|
|
|
|
r.set(f"trade.{trade_id}.reference", reference)
|
|
|
|
r.set(f"trade.{trade_id}.reference", reference)
|
|
|
|
to_store = {
|
|
|
|
to_store = {
|
|
|
|
"id": trade_id,
|
|
|
|
"id": trade_id,
|
|
|
|
|
|
|
|
"tx": "",
|
|
|
|
"asset": asset,
|
|
|
|
"asset": asset,
|
|
|
|
"buyer": buyer,
|
|
|
|
"buyer": buyer,
|
|
|
|
"currency": currency,
|
|
|
|
"currency": currency,
|
|
|
@ -317,6 +428,7 @@ class Transactions(util.Base):
|
|
|
|
"amount_crypto": amount_crypto,
|
|
|
|
"amount_crypto": amount_crypto,
|
|
|
|
"reference": reference,
|
|
|
|
"reference": reference,
|
|
|
|
"provider": provider,
|
|
|
|
"provider": provider,
|
|
|
|
|
|
|
|
"subclass": subclass,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.log.info(f"Storing trade information: {str(to_store)}")
|
|
|
|
self.log.info(f"Storing trade information: {str(to_store)}")
|
|
|
|
r.hmset(f"trade.{reference}", to_store)
|
|
|
|
r.hmset(f"trade.{reference}", to_store)
|
|
|
@ -393,6 +505,20 @@ class Transactions(util.Base):
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
return ref_data
|
|
|
|
return ref_data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_tx(self, tx):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Get the transaction information for a transaction ID.
|
|
|
|
|
|
|
|
:param reference: trade reference
|
|
|
|
|
|
|
|
:type reference: string
|
|
|
|
|
|
|
|
:return: dict of trade information
|
|
|
|
|
|
|
|
:rtype: dict
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
tx_data = r.hgetall(f"tx.{tx}")
|
|
|
|
|
|
|
|
tx_data = util.convert(tx_data)
|
|
|
|
|
|
|
|
if not tx_data:
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
return tx_data
|
|
|
|
|
|
|
|
|
|
|
|
def del_ref(self, reference):
|
|
|
|
def del_ref(self, reference):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Delete a given reference from the Redis database.
|
|
|
|
Delete a given reference from the Redis database.
|
|
|
|