diff --git a/handler/agora.py b/handler/agora.py index 39cff7d..1fd6596 100644 --- a/handler/agora.py +++ b/handler/agora.py @@ -95,16 +95,15 @@ class Agora(object): reference = self.tx.tx_to_ref(contact_id) buyer = contact["data"]["buyer"]["username"] amount = contact["data"]["amount"] - if "amount_xmr" in contact["data"]: + asset = contact["data"]["advertisement"]["asset"] + if asset == "XMR": amount_crypto = contact["data"]["amount_xmr"] - crypto = "XMR" - elif "amount_btc" in contact["data"]: + elif asset == "BTC": amount_crypto = contact["data"]["amount_btc"] - crypto = "BTC" currency = contact["data"]["currency"] if not contact["data"]["is_selling"]: continue - rtrn.append(f"{reference}: {buyer} {amount}{currency} {amount_crypto}{crypto}") + rtrn.append(f"{reference}: {buyer} {amount}{currency} {amount_crypto}{asset}") return rtrn def dashboard_hook(self, dash): @@ -123,22 +122,21 @@ class Agora(object): current_trades.append(reference) buyer = contact["data"]["buyer"]["username"] amount = contact["data"]["amount"] - if "amount_xmr" in contact["data"]: + asset = contact["data"]["advertisement"]["asset"] + if asset == "XMR": amount_crypto = contact["data"]["amount_xmr"] - crypto = "XMR" - elif "amount_btc" in contact["data"]: + elif asset == "BTC": amount_crypto = contact["data"]["amount_btc"] - crypto = "BTC" currency = contact["data"]["currency"] if not contact["data"]["is_selling"]: continue if reference not in self.last_dash: - reference = self.tx.new_trade(contact_id, buyer, currency, amount, amount_xmr) + reference = self.tx.new_trade(asset, contact_id, buyer, currency, amount, amount_crypto) if reference: if reference not in current_trades: current_trades.append(reference) # Let us know there is a new trade - self.irc.sendmsg(f"AUTO {reference}: {buyer} {amount}{currency} {amount_crypto}{crypto}") + self.irc.sendmsg(f"AUTO {reference}: {buyer} {amount}{currency} {amount_crypto}{asset}") # Note that we have seen this reference self.last_dash.add(reference) @@ -167,12 +165,11 @@ class Agora(object): contact_id = contact["data"]["contact_id"] buyer = contact["data"]["buyer"]["username"] amount = contact["data"]["amount"] - if "amount_xmr" in contact["data"]: + asset = contact["data"]["advertisement"]["asset"] + if asset == "XMR": amount_crypto = contact["data"]["amount_xmr"] - crypto = "XMR" - elif "amount_btc" in contact["data"]: + elif asset == "BTC": amount_crypto = contact["data"]["amount_btc"] - crypto = "BTC" currency = contact["data"]["currency"] release_url = contact["actions"]["release_url"] if not contact["data"]["is_selling"]: @@ -180,7 +177,7 @@ class Agora(object): reference = self.tx.tx_to_ref(contact_id) if not reference: reference = "not_set" - dash_tmp.append(f"{reference}: {buyer} {amount}{currency} {amount_crypto}{crypto} {release_url}") + dash_tmp.append(f"{reference}: {buyer} {amount}{currency} {amount_crypto}{asset} {release_url}") return dash_tmp @@ -443,10 +440,12 @@ class Agora(object): max_local = max_usd * rates[currency] return (min_local, max_local) - def create_ad(self, countrycode, currency): + def create_ad(self, asset, countrycode, currency): """ - Post an ad in a country with a given currency. + Post an ad with the given asset in a country with a given currency. Convert the min and max amounts from settings to the given currency with CurrencyRates. + :param asset: the crypto asset to list (XMR or BTC) + :type asset: string :param countrycode: country code :param currency: currency code :type countrycode: string @@ -463,6 +462,7 @@ class Agora(object): else: adtext = ad.replace("$PAYMENT$", settings.Agora.DefaultDetailsAd) paymentdetailstext = paymentdetails.replace("$PAYMENT$", settings.Agora.DefaultDetailsPayment) + ad = ad.replace("$ASSET$", asset) rates = self.get_rates_all() if currency == "USD": min_amount = float(settings.Agora.MinUSD) @@ -478,7 +478,7 @@ class Agora(object): country_code=countrycode, currency=currency, trade_type="ONLINE_SELL", - asset="XMR", + asset=asset, price_equation=price_formula, track_max_amount=False, require_trusted_by_advertiser=False, @@ -500,52 +500,53 @@ class Agora(object): :return: False or dict with response :rtype: bool or dict """ - for currency, countrycode in loads(settings.Agora.DistList): - rtrn = self.create_ad(countrycode, currency) - if not rtrn: - return False - yield rtrn - - def get_combinations(self): - """ - Get all combinations of currencies and countries from the configuration. - :return: list of [country, currency] - :rtype: list - """ - currencies = loads(settings.Agora.BruteCurrencies) - countries = loads(settings.Agora.BruteCountries) - combinations = [[country, currency] for country in countries for currency in currencies] - return combinations - - def dist_bruteforce(self): - """ - Bruteforce all possible ads from the currencies and countries in the config. - Does not exit on errors. - :return: False or dict with response - :rtype: bool or dict - """ - combinations = self.get_combinations() - for country, currency in combinations: - rtrn = self.create_ad(country, currency) - if not rtrn: - yield False - yield rtrn - - def bruteforce_fill_blanks(self): - """ - Get the ads that we want to configure but have not, and fill in the blanks. - :return: False or dict with response - :rtype: bool or dict - """ - existing_ads = self.enum_ads() - combinations = self.get_combinations() - for country, currency in combinations: - if not [country, currency] in existing_ads: - rtrn = self.create_ad(country, currency) + for asset in loads(settings.Agora.AssetList): + for currency, countrycode in loads(settings.Agora.DistList): + rtrn = self.create_ad(asset, countrycode, currency) if not rtrn: - yield False + return False yield rtrn + # def get_combinations(self): + # """ + # Get all combinations of currencies and countries from the configuration. + # :return: list of [country, currency] + # :rtype: list + # """ + # currencies = loads(settings.Agora.BruteCurrencies) + # countries = loads(settings.Agora.BruteCountries) + # combinations = [[country, currency] for country in countries for currency in currencies] + # return combinations + +# def dist_bruteforce(self): +# """ +# Bruteforce all possible ads from the currencies and countries in the config. +# Does not exit on errors. +# :return: False or dict with response +# :rtype: bool or dict +# """ +# combinations = self.get_combinations() +# for country, currency in combinations: +# rtrn = self.create_ad(country, currency) +# if not rtrn: +# yield False +# yield rtrn +# +# def bruteforce_fill_blanks(self): +# """ +# Get the ads that we want to configure but have not, and fill in the blanks. +# :return: False or dict with response +# :rtype: bool or dict +# """ +# existing_ads = self.enum_ads() +# combinations = self.get_combinations() +# for country, currency in combinations: +# if not [country, currency] in existing_ads: +# rtrn = self.create_ad(country, currency) +# if not rtrn: +# yield False +# yield rtrn + def strip_duplicate_ads(self): """ Remove duplicate ads. diff --git a/handler/commands.py b/handler/commands.py index 02329de..77d0b85 100644 --- a/handler/commands.py +++ b/handler/commands.py @@ -33,11 +33,15 @@ class IRCCommands(object): """ Post an ad on AgoraDesk with the given country and currency code. """ - posted = agora.create_ad(spl[1], spl[2]) - if posted["success"]: - msg(f"{posted['response']['data']['message']}: {posted['response']['data']['ad_id']}") - else: - msg(dumps(posted["response"])) + if length == 4: + if spl[1] not in loads(settings.Agora.AssetList): + msg(f"Not a valid asset: {spl[1]}") + return + posted = agora.create_ad(spl[1], spl[2], spl[3]) + if posted["success"]: + msg(f"{posted['response']['data']['message']}: {posted['response']['data']['ad_id']}") + else: + msg(dumps(posted["response"])) class messages(object): name = "messages" @@ -87,31 +91,31 @@ class IRCCommands(object): else: msg(x["response"]["data"]["message"]) - class brute(object): - name = "brute" - authed = True - helptext = "Use a bruteforce algorithm to create all possible currency and country pairs." - - @staticmethod - def run(cmd, spl, length, authed, msg, agora, revolut, tx): - for x in agora.dist_bruteforce(): - if x["success"]: - msg(f"{x['response']['data']['message']}: {x['response']['data']['ad_id']}") - else: - msg(dumps(x)) - - class fillblanks(object): - name = "fillblanks" - authed = True - helptext = "Resume a run of brute by getting all our adverts then filling the blanks." - - @staticmethod - def run(cmd, spl, length, authed, msg, agora, revolut, tx): - for x in agora.bruteforce_fill_blanks(): - if x["success"]: - msg(f"{x['response']['data']['message']}: {x['response']['data']['ad_id']}") - else: - msg(dumps(x)) +# class brute(object): +# name = "brute" +# authed = True +# helptext = "Use a bruteforce algorithm to create all possible currency and country pairs." +# +# @staticmethod +# def run(cmd, spl, length, authed, msg, agora, revolut, tx): +# for x in agora.dist_bruteforce(): +# if x["success"]: +# msg(f"{x['response']['data']['message']}: {x['response']['data']['ad_id']}") +# else: +# msg(dumps(x)) +# +# class fillblanks(object): +# name = "fillblanks" +# authed = True +# helptext = "Resume a run of brute by getting all our adverts then filling the blanks." +# +# @staticmethod +# def run(cmd, spl, length, authed, msg, agora, revolut, tx): +# for x in agora.bruteforce_fill_blanks(): +# if x["success"]: +# msg(f"{x['response']['data']['message']}: {x['response']['data']['ad_id']}") +# else: +# msg(dumps(x)) class stripdupes(object): name = "stripdupes" @@ -190,16 +194,30 @@ class IRCCommands(object): if total_usd_revolut is False: msg("Error getting Revolut balance.") return - agora_wallet = agora.agora.wallet_balance_xmr() - if not agora_wallet["success"]: - msg("Error getting Agora balance.") + agora_wallet_xmr = agora.agora.wallet_balance_xmr() + if not agora_wallet_xmr["success"]: + msg("Error getting Agora XMR balance.") return - total_xmr_agora = agora_wallet["response"]["data"]["total"]["balance"] + agora_wallet_btc = agora.agora.wallet_balance_btc() + if not agora_wallet_btc["success"]: + msg("Error getting Agora BTC balance.") + return + total_xmr_agora = agora_wallet_xmr["response"]["data"]["total"]["balance"] + total_btc_agora = agora_wallet_btc["response"]["data"]["total"]["balance"] # Get the XMR -> USD exchange rate xmr_usd = agora.cg.get_price(ids="monero", vs_currencies=["USD"]) + # Get the BTC -> USD exchange rate + btc_usd = agora.cg.get_price(ids="bitcoin", vs_currencies=["USD"]) + # Convert the Agora XMR total to USD - total_usd_agora = float(total_xmr_agora) * xmr_usd["monero"]["usd"] + total_usd_agora_xmr = float(total_xmr_agora) * xmr_usd["monero"]["usd"] + + # Convert the Agora BTC total to USD + total_usd_agora_btc = float(total_btc_agora) * btc_usd["bitcoin"]["usd"] + + # Add it all up + total_usd_agora = total_usd_agora_xmr + total_usd_agora_btc total_usd = total_usd_agora + total_usd_revolut # Convert the total USD price to GBP and SEK @@ -315,16 +333,22 @@ class IRCCommands(object): class wallet(object): name = "wallet" authed = True - helptext = "Get Agora wallet balance in XMR." + helptext = "Get Agora wallet balances." @staticmethod def run(cmd, spl, length, authed, msg, agora, revolut, tx): - rtrn = agora.agora.wallet_balance_xmr() - if not rtrn["success"]: - msg("Error getting wallet details.") + rtrn_xmr = agora.agora.wallet_balance_xmr() + if not rtrn_xmr["success"]: + msg("Error getting XMR wallet details.") + return + rtrn_btc = agora.agora.wallet_balance() + if not rtrn_btc["success"]: + msg("Error getting BTC wallet details.") return - balance = rtrn["response"]["data"]["total"]["balance"] - msg(f"Wallet balance: {balance}XMR") + balance_xmr = rtrn_xmr["response"]["data"]["total"]["balance"] + balance_btc = rtrn_btc["response"]["data"]["total"]["balance"] + msg(f"XMR wallet balance: {balance_xmr}") + msg(f"BTC wallet balance: {balance_btc}") class pubads(object): name = "pubads" diff --git a/handler/transactions.py b/handler/transactions.py index 902aa68..c46598b 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -183,22 +183,23 @@ class Transactions(object): message_long = rtrn["response"]["data"]["message"] self.irc.sendmsg(f"{message} - {message_long}") - def new_trade(self, trade_id, buyer, currency, amount, amount_xmr): + def new_trade(self, asset, trade_id, buyer, currency, amount, amount_crypto): """ Called when we have a new trade in Agora. Store details in Redis, generate a reference and optionally let the customer know the reference. """ reference = "".join(choices(ascii_uppercase, k=5)) - reference = f"XMR-{reference}" + reference = f"{asset}-{reference}" existing_ref = r.get(f"trade.{trade_id}.reference") if not existing_ref: r.set(f"trade.{trade_id}.reference", reference) to_store = { "id": trade_id, + "asset": asset, "buyer": buyer, "currency": currency, "amount": amount, - "amount_xmr": amount_xmr, + "amount_crypto": amount_crypto, "reference": reference, } self.log.info("Storing trade information: {info}", info=str(to_store))