From 19724eac7789172a1ef13f92e90d40c9612e12eb Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 1 Jan 2022 19:20:20 +0000 Subject: [PATCH 1/5] Implement looking up trade by partial reference message or amount/currency --- handler/transactions.py | 76 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/handler/transactions.py b/handler/transactions.py index 7aef36a..64fd660 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -76,8 +76,47 @@ class Transactions(object): self.log.info("Transaction processed: {formatted}", formatted=dumps(to_store, indent=2)) r.hmset(f"tx.{txid}", to_store) self.irc.sendmsg(f"AUTO Incoming transaction: {amount}{currency} ({reference}) - {state} - {description}") - # Try getting the trade by the reference ID given - stored_trade = self.get_ref(reference) + # Account for silly people not removing the default string + # Split the reference into parts + ref_split = reference.split(" ") + # Get all existing references + existing_refs = self.get_refs() + print("Existing references:", existing_refs) + # Get all parts of the given reference split that match the existing references + stored_trade_reference = set(existing_refs).intersection(set(ref_split)) + if len(stored_trade_reference) > 1: + self.log.error("Multiple references valid for TXID {txid}: {reference}", txid=txid, reference=reference) + self.irc.sendmsg(f"Multiple references valid for TXID {txid}: {reference}") + return + print("Stored trade reference:", stored_trade_reference) + + stored_trade = False + if not stored_trade_reference: + self.log.info(f"No reference in DB refs for {reference}", reference=reference) + self.irc.sendmsg(f"No reference in DB refs for {reference}") + # Try checking just amount and currency, as some people (usually people buying small amounts) + # are unable to put in a reference properly. + + self.log.info("Checking against amount and currency for TXID {txid}", txid=txid) + self.irc.sendmsg(f"Checking against amount and currency for TXID {txid}") + stored_trade = self.find_trade(txid, currency, amount) + if not stored_trade: + self.log.info( + "Failed to get reference by amount and currency: {txid} {currency} {amount}", + txid=txid, + currency=currency, + amount=amount, + ) + self.irc.sendmsg(f"Failed to get reference by amount and currency: {txid} {currency} {amount}") + return + if amount > settings.Agora.AcceptableAltLookupUSD: + self.log.info("Not checking against amount and currency as amount exceeds MAX") + self.irc.sendmsg(f"Not checking against amount and currency as amount exceeds MAX") + # Close here if the amount exceeds the allowable limit for no reference + return + if not stored_trade: + stored_trade = self.get_ref(stored_trade_reference.pop()) + print("Stored trade:", stored_trade) if not stored_trade: self.log.info(f"No reference in DB for {reference}", reference=reference) self.irc.sendmsg(f"No reference in DB for {reference}") @@ -103,10 +142,11 @@ class Transactions(object): if not account_type == "revolut": self.irc.sendmsg(f"Account type is not Revolut: {account_type}") return - self.irc.sendmsg(f"All checks passed, releasing funds for {stored_trade['id']} / {reference}") - rtrn = self.agora.release_funds(stored_trade["id"]) - self.agora.agora.contact_message_post(stored_trade["id"], "Thanks! Releasing now :)") - self.irc.sendmsg(dumps(rtrn)) + # self.irc.sendmsg(f"All checks passed, releasing funds for {stored_trade['id']} / {reference}") + # rtrn = self.agora.release_funds(stored_trade["id"]) + # self.agora.agora.contact_message_post(stored_trade["id"], "Thanks! Releasing now :)") + # self.irc.sendmsg(dumps(rtrn)) + self.irc.sendmsg(f"DRY RUN releasing funds for {stored_trade['id']} / {reference}") def new_trade(self, trade_id, buyer, currency, amount, amount_xmr): """ @@ -156,6 +196,30 @@ class Transactions(object): return "AMOUNT_INVALID" return False + def find_trade(self, txid, currency, amount): + """ + Get a trade reference that matches the given currency and amount. + Only works if there is one result. + :param txid: Revolut transaction ID + :param currency: currency + :param amount: amount + :type txid: string + :type currency: string + :type amount: int + :return: matching trade object or False + :rtype: dict or bool + """ + refs = self.get_refs() + matching_refs = [] + for ref in refs: + stored_trade = self.get_ref(ref) + if stored_trade["currency"] == currency and stored_trade["amount"] == amount: + matching_refs.append(stored_trade) + if len(matching_refs) != 1: + self.log.error("Find trade returned multiple results for TXID {txid}: {matching_refs}", txid=txid, matching_refs=matching_refs) + return False + return matching_refs[0] + def get_refs(self): """ Get all reference IDs for trades. From 5ea1c26a84c50e64a4dd694a0f27ad6a730c4ee8 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 1 Jan 2022 19:33:15 +0000 Subject: [PATCH 2/5] Don't check non-exact values if we looked up without reference --- handler/transactions.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/handler/transactions.py b/handler/transactions.py index 64fd660..1279ceb 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -76,6 +76,8 @@ class Transactions(object): self.log.info("Transaction processed: {formatted}", formatted=dumps(to_store, indent=2)) r.hmset(f"tx.{txid}", to_store) self.irc.sendmsg(f"AUTO Incoming transaction: {amount}{currency} ({reference}) - {state} - {description}") + + # Partial reference implementation # Account for silly people not removing the default string # Split the reference into parts ref_split = reference.split(" ") @@ -91,6 +93,9 @@ class Transactions(object): print("Stored trade reference:", stored_trade_reference) stored_trade = False + looked_up_without_reference = False + + # Amount/currency lookup implementation if not stored_trade_reference: self.log.info(f"No reference in DB refs for {reference}", reference=reference) self.irc.sendmsg(f"No reference in DB refs for {reference}") @@ -114,6 +119,8 @@ class Transactions(object): self.irc.sendmsg(f"Not checking against amount and currency as amount exceeds MAX") # Close here if the amount exceeds the allowable limit for no reference return + # Note that we have looked it up without reference so we don't use +- below + looked_up_without_reference = True if not stored_trade: stored_trade = self.get_ref(stored_trade_reference.pop()) print("Stored trade:", stored_trade) @@ -132,6 +139,8 @@ class Transactions(object): # Make sure the expected amount was sent if not stored_trade["amount"] == amount: + if looked_up_without_reference: + return # If the amount does not match exactly, get the min and max values for our given acceptable margins for trades min_amount, max_amount = self.agora.get_acceptable_margins(currency, amount) self.irc.sendmsg(f"Amount does not match exactly, trying with margins: min: {min_amount} / max: {max_amount}") From bc68bcd74f8e5456d7e6b95c72b029bd1eb497be Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 1 Jan 2022 20:01:01 +0000 Subject: [PATCH 3/5] Use the right variable to check amount --- handler/transactions.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/handler/transactions.py b/handler/transactions.py index 1279ceb..0be9144 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -114,12 +114,19 @@ class Transactions(object): ) self.irc.sendmsg(f"Failed to get reference by amount and currency: {txid} {currency} {amount}") return - if amount > settings.Agora.AcceptableAltLookupUSD: + if currency == "USD": + amount_usd = amount + else: + rates = self.get_rates_all() + amount_usd = amount / rates[currency] + # Amount is reliable here as it is checked by find_trade, so no need for stored_trade["amount"] + if amount_usd > settings.Agora.AcceptableAltLookupUSD: self.log.info("Not checking against amount and currency as amount exceeds MAX") self.irc.sendmsg(f"Not checking against amount and currency as amount exceeds MAX") # Close here if the amount exceeds the allowable limit for no reference return # Note that we have looked it up without reference so we don't use +- below + # This might be redundant given the amount checks in find_trade, but better safe than sorry! looked_up_without_reference = True if not stored_trade: stored_trade = self.get_ref(stored_trade_reference.pop()) From 4053dce0484636d1060e3b0e95211128d5e88c1e Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 1 Jan 2022 20:22:53 +0000 Subject: [PATCH 4/5] Fix alt reference implementation --- handler/transactions.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/handler/transactions.py b/handler/transactions.py index 0be9144..d1e0f00 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -83,14 +83,12 @@ class Transactions(object): ref_split = reference.split(" ") # Get all existing references existing_refs = self.get_refs() - print("Existing references:", existing_refs) # Get all parts of the given reference split that match the existing references stored_trade_reference = set(existing_refs).intersection(set(ref_split)) if len(stored_trade_reference) > 1: self.log.error("Multiple references valid for TXID {txid}: {reference}", txid=txid, reference=reference) self.irc.sendmsg(f"Multiple references valid for TXID {txid}: {reference}") return - print("Stored trade reference:", stored_trade_reference) stored_trade = False looked_up_without_reference = False @@ -117,10 +115,10 @@ class Transactions(object): if currency == "USD": amount_usd = amount else: - rates = self.get_rates_all() + rates = self.agora.get_rates_all() amount_usd = amount / rates[currency] # Amount is reliable here as it is checked by find_trade, so no need for stored_trade["amount"] - if amount_usd > settings.Agora.AcceptableAltLookupUSD: + if float(amount_usd) > float(settings.Agora.AcceptableAltLookupUSD): self.log.info("Not checking against amount and currency as amount exceeds MAX") self.irc.sendmsg(f"Not checking against amount and currency as amount exceeds MAX") # Close here if the amount exceeds the allowable limit for no reference @@ -130,7 +128,6 @@ class Transactions(object): looked_up_without_reference = True if not stored_trade: stored_trade = self.get_ref(stored_trade_reference.pop()) - print("Stored trade:", stored_trade) if not stored_trade: self.log.info(f"No reference in DB for {reference}", reference=reference) self.irc.sendmsg(f"No reference in DB for {reference}") @@ -158,11 +155,10 @@ class Transactions(object): if not account_type == "revolut": self.irc.sendmsg(f"Account type is not Revolut: {account_type}") return - # self.irc.sendmsg(f"All checks passed, releasing funds for {stored_trade['id']} / {reference}") + self.irc.sendmsg(f"All checks passed, releasing funds for {stored_trade['id']} / {reference}") # rtrn = self.agora.release_funds(stored_trade["id"]) # self.agora.agora.contact_message_post(stored_trade["id"], "Thanks! Releasing now :)") # self.irc.sendmsg(dumps(rtrn)) - self.irc.sendmsg(f"DRY RUN releasing funds for {stored_trade['id']} / {reference}") def new_trade(self, trade_id, buyer, currency, amount, amount_xmr): """ @@ -229,7 +225,7 @@ class Transactions(object): matching_refs = [] for ref in refs: stored_trade = self.get_ref(ref) - if stored_trade["currency"] == currency and stored_trade["amount"] == amount: + if stored_trade["currency"] == currency and float(stored_trade["amount"]) == float(amount): matching_refs.append(stored_trade) if len(matching_refs) != 1: self.log.error("Find trade returned multiple results for TXID {txid}: {matching_refs}", txid=txid, matching_refs=matching_refs) From faa71dc2edb6ace8555f49d1738a7f48d9508b3f Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 1 Jan 2022 20:27:30 +0000 Subject: [PATCH 5/5] Add more debugging --- handler/transactions.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/handler/transactions.py b/handler/transactions.py index d1e0f00..cbcc991 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -129,7 +129,7 @@ class Transactions(object): if not stored_trade: stored_trade = self.get_ref(stored_trade_reference.pop()) if not stored_trade: - self.log.info(f"No reference in DB for {reference}", reference=reference) + self.log.info("No reference in DB for {reference}", reference=reference) self.irc.sendmsg(f"No reference in DB for {reference}") return @@ -138,6 +138,11 @@ class Transactions(object): # Make sure it was sent in the expected currency if not stored_trade["currency"] == currency: + self.log.info( + "Currency mismatch, Agora: {currency_agora} / Revolut: {currency}", + currency_agora=stored_trade["currency"], + currency=currency, + ) self.irc.sendmsg(f"Currency mismatch, Agora: {stored_trade['currency']} / Revolut: {currency}") return @@ -147,14 +152,27 @@ class Transactions(object): return # If the amount does not match exactly, get the min and max values for our given acceptable margins for trades min_amount, max_amount = self.agora.get_acceptable_margins(currency, amount) + self.log.info( + "Amount does not match exactly, trying with margins: min: {min_amount} / max: {max_amount}", + min_amount=min_amount, + max_amount=max_amount, + ) self.irc.sendmsg(f"Amount does not match exactly, trying with margins: min: {min_amount} / max: {max_amount}") if not min_amount < stored_trade["amount"] < max_amount: + self.log.info( + "Amount mismatch - not in margins: {amount} (min: {min_amount} / max: {max_amount}", + amount=stored_trade["amount"], + min_amount=min_amount, + max_amount=max_amount, + ) self.irc.sendmsg(f"Amount mismatch - not in margins: {stored_trade['amount']} (min: {min_amount} / max: {max_amount}") return # Make sure the account type was Revolut, as these are completed instantly if not account_type == "revolut": + self.log.info("Account type is not Revolut: {account_type}", account_type=account_type) self.irc.sendmsg(f"Account type is not Revolut: {account_type}") return + self.log.info("All checks passed, releasing funds for {trade_id} {reference}", trade_id=stored_trade["id"], reference=reference) self.irc.sendmsg(f"All checks passed, releasing funds for {stored_trade['id']} / {reference}") # rtrn = self.agora.release_funds(stored_trade["id"]) # self.agora.agora.contact_message_post(stored_trade["id"], "Thanks! Releasing now :)")