Remove calls to Revolut

This commit is contained in:
Mark Veidemanis 2022-03-04 22:15:53 +00:00
parent b53fbfc905
commit 2266300064
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
4 changed files with 33 additions and 342 deletions

View File

@ -12,7 +12,6 @@ from signal import signal, SIGINT
# Project imports # Project imports
from settings import settings from settings import settings
import util import util
from revolut import Revolut
from agora import Agora from agora import Agora
from transactions import Transactions from transactions import Transactions
from irc import bot from irc import bot
@ -99,7 +98,6 @@ if __name__ == "__main__":
"irc": bot(), "irc": bot(),
"agora": Agora(), "agora": Agora(),
"markets": Markets(), "markets": Markets(),
"revolut": Revolut(),
"nordigen": Nordigen(), "nordigen": Nordigen(),
"truelayer": TrueLayer(), "truelayer": TrueLayer(),
"fidor": Fidor(), "fidor": Fidor(),
@ -110,21 +108,6 @@ if __name__ == "__main__":
# Merge all classes into each other # Merge all classes into each other
util.xmerge_attrs(init_map) util.xmerge_attrs(init_map)
# Setup the authcode -> refresh token and refresh_token -> auth_token stuff
# util.setup_call_loops(
# token_setting=settings.Revolut.SetupToken,
# function_init=init_map["revolut"].setup_auth,
# function_continuous=init_map["revolut"].get_new_token,
# delay=int(settings.Revolut.RefreshSec),
# function_post_start=init_map["revolut"].setup_webhook,
# )
# util.setup_call_loops(
# token_setting=settings.TrueLayer.SetupToken,
# function_init=init_map["truelayer"].setup_auth,
# function_continuous=init_map["truelayer"].get_new_token,
# delay=int(settings.TrueLayer.RefreshSec),
# )
# Set up the loops to put data in ES # Set up the loops to put data in ES
init_map["tx"].setup_loops() init_map["tx"].setup_loops()

View File

@ -12,7 +12,7 @@ class IRCCommands(object):
helptext = "Get all open trades." helptext = "Get all open trades."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
""" """
Get details of open trades and post on IRC. Get details of open trades and post on IRC.
""" """
@ -32,7 +32,7 @@ class IRCCommands(object):
helptext = "Create an ad. Usage: create <XMR/BTC> <country> <currency> [<provider>]" helptext = "Create an ad. Usage: create <XMR/BTC> <country> <currency> [<provider>]"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
""" """
Post an ad on AgoraDesk with the given country and currency code. Post an ad on AgoraDesk with the given country and currency code.
""" """
@ -64,7 +64,7 @@ class IRCCommands(object):
helptext = "Get messages. Usage: messages [<reference>]" helptext = "Get messages. Usage: messages [<reference>]"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
""" """
Get all messages for all open trades or a given trade. Get all messages for all open trades or a given trade.
""" """
@ -98,7 +98,7 @@ class IRCCommands(object):
helptext = "Distribute all our chosen currency and country ad pairs. Usage: dist [<XMR/BTC>]" helptext = "Distribute all our chosen currency and country ad pairs. Usage: dist [<XMR/BTC>]"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
# Distribute out our ad to all countries in the config # Distribute out our ad to all countries in the config
if length == 2: if length == 2:
asset = spl[1] asset = spl[1]
@ -123,7 +123,7 @@ class IRCCommands(object):
helptext = "Update all ads with details." helptext = "Update all ads with details."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
for x in agora.redist_countries(): for x in agora.redist_countries():
if x[0]["success"]: if x[0]["success"]:
msg(f"{x[0]['response']['data']['message']}: {x[1]}") msg(f"{x[0]['response']['data']['message']}: {x[1]}")
@ -136,51 +136,17 @@ class IRCCommands(object):
helptext = "Remove all duplicate adverts." helptext = "Remove all duplicate adverts."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
rtrn = agora.strip_duplicate_ads() rtrn = agora.strip_duplicate_ads()
msg(dumps(rtrn)) msg(dumps(rtrn))
class accounts(object):
name = "accounts"
authed = True
helptext = "Get all account information from Revolut."
@staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify):
accounts = revolut.accounts()
accounts_posted = 0
if accounts is None:
msg("Error getting accounts.")
for account in accounts:
if account["balance"] > 0:
if "name" in account:
name = account["name"]
else:
name = "not_set"
msg(f"{name} {account['currency']}: {account['balance']}")
accounts_posted += 1
if accounts_posted == 0:
msg("No accounts with balances.")
class balance(object):
name = "balance"
authed = True
helptext = "Get total account balance from Revolut in USD."
@staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify):
total_usd = revolut.get_total_usd()
if total_usd is False:
msg("Error getting total balance.")
msg(f"Total: {round(total_usd, 2)}USD")
class total(object): class total(object):
name = "total" name = "total"
authed = True authed = True
helptext = "Get total account balance from Revolut and Agora." helptext = "Get total account balance from Sinks and Agora."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
totals_all = tx.get_total() totals_all = tx.get_total()
totals = totals_all[0] totals = totals_all[0]
wallets = totals_all[1] wallets = totals_all[1]
@ -202,7 +168,7 @@ class IRCCommands(object):
helptext = "Summon all operators." helptext = "Summon all operators."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
notify.sendmsg("You have been summoned!") notify.sendmsg("You have been summoned!")
class message(object): class message(object):
@ -211,7 +177,7 @@ class IRCCommands(object):
helptext = "Send a message on a trade. Usage: msg <reference> <message...>" helptext = "Send a message on a trade. Usage: msg <reference> <message...>"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length > 2: if length > 2:
full_msg = " ".join(spl[2:]) full_msg = " ".join(spl[2:])
reference = tx.ref_to_tx(spl[1]) reference = tx.ref_to_tx(spl[1])
@ -227,7 +193,7 @@ class IRCCommands(object):
helptext = "List all references" helptext = "List all references"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
msg(f"References: {', '.join(tx.get_refs())}") msg(f"References: {', '.join(tx.get_refs())}")
class ref(object): class ref(object):
@ -236,7 +202,7 @@ class IRCCommands(object):
helptext = "Get more information about a reference. Usage: ref <reference>" helptext = "Get more information about a reference. Usage: ref <reference>"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length == 2: if length == 2:
ref_data = tx.get_ref(spl[1]) ref_data = tx.get_ref(spl[1])
if not ref_data: if not ref_data:
@ -250,7 +216,7 @@ class IRCCommands(object):
helptext = "Delete a reference. Usage: del <reference>" helptext = "Delete a reference. Usage: del <reference>"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length == 2: if length == 2:
ref_data = tx.get_ref(spl[1]) ref_data = tx.get_ref(spl[1])
if not ref_data: if not ref_data:
@ -265,7 +231,7 @@ class IRCCommands(object):
helptext = "Release funds for a trade. Usage: release <reference>" helptext = "Release funds for a trade. Usage: release <reference>"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length == 2: if length == 2:
tx = tx.ref_to_tx(spl[1]) tx = tx.ref_to_tx(spl[1])
if not tx: if not tx:
@ -282,7 +248,7 @@ class IRCCommands(object):
helptext = "Delete all our adverts." helptext = "Delete all our adverts."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
rtrn = agora.nuke_ads() rtrn = agora.nuke_ads()
msg(dumps(rtrn)) msg(dumps(rtrn))
@ -292,7 +258,7 @@ class IRCCommands(object):
helptext = "Get Agora wallet balances." helptext = "Get Agora wallet balances."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
rtrn_xmr = agora.agora.wallet_balance_xmr() rtrn_xmr = agora.agora.wallet_balance_xmr()
if not rtrn_xmr["success"]: if not rtrn_xmr["success"]:
msg("Error getting XMR wallet details.") msg("Error getting XMR wallet details.")
@ -312,7 +278,7 @@ class IRCCommands(object):
helptext = "View public adverts. Usage: pubads <XMR/BTC> <currency> [<provider,...>]" helptext = "View public adverts. Usage: pubads <XMR/BTC> <currency> [<provider,...>]"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length == 3: if length == 3:
asset = spl[1] asset = spl[1]
if asset not in loads(settings.Agora.AssetList): if asset not in loads(settings.Agora.AssetList):
@ -345,7 +311,7 @@ class IRCCommands(object):
helptext = "Cheat the markets by manipulating our prices to exploit people. Usage: cheat [<XMR/BTC>]" helptext = "Cheat the markets by manipulating our prices to exploit people. Usage: cheat [<XMR/BTC>]"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length == 1: if length == 1:
agora.run_cheat_in_thread() agora.run_cheat_in_thread()
msg("Running cheat in thread.") msg("Running cheat in thread.")
@ -363,7 +329,7 @@ class IRCCommands(object):
helptext = "Run the next currency for cheat." helptext = "Run the next currency for cheat."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
if length == 1: if length == 1:
asset = agora.run_cheat_in_thread() asset = agora.run_cheat_in_thread()
msg(f"Running next asset for cheat in thread: {asset}") msg(f"Running next asset for cheat in thread: {asset}")
@ -374,7 +340,7 @@ class IRCCommands(object):
helptext = "Get all our ad regions" helptext = "Get all our ad regions"
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
ads = agora.enum_ads() ads = agora.enum_ads()
for ad in ads: for ad in ads:
msg(f"({ad[0]}) {ad[1]} {ad[2]} {ad[3]} {ad[4]}") msg(f"({ad[0]}) {ad[1]} {ad[2]} {ad[3]} {ad[4]}")
@ -385,7 +351,7 @@ class IRCCommands(object):
helptext = "Get current XMR price." helptext = "Get current XMR price."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
xmr_prices = agora.cg.get_price(ids="monero", vs_currencies=["sek", "usd", "gbp"]) xmr_prices = agora.cg.get_price(ids="monero", vs_currencies=["sek", "usd", "gbp"])
price_sek = xmr_prices["monero"]["sek"] price_sek = xmr_prices["monero"]["sek"]
price_usd = xmr_prices["monero"]["usd"] price_usd = xmr_prices["monero"]["usd"]
@ -398,7 +364,7 @@ class IRCCommands(object):
helptext = "Get current BTC price." helptext = "Get current BTC price."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
xmr_prices = agora.cg.get_price(ids="bitcoin", vs_currencies=["sek", "usd", "gbp"]) xmr_prices = agora.cg.get_price(ids="bitcoin", vs_currencies=["sek", "usd", "gbp"])
price_sek = xmr_prices["bitcoin"]["sek"] price_sek = xmr_prices["bitcoin"]["sek"]
price_usd = xmr_prices["bitcoin"]["usd"] price_usd = xmr_prices["bitcoin"]["usd"]
@ -411,28 +377,16 @@ class IRCCommands(object):
helptext = "Take profit." helptext = "Take profit."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
agora.withdraw_funds() agora.withdraw_funds()
class shuffle(object):
name = "shuffle"
authed = True
helptext = "Convert all currencies in Revolut to supplied one. Usage: shuffle <currency>"
@staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify):
if length == 2:
currency = spl[1]
rtrn = revolut.shuffle(currency)
msg(dumps(rtrn))
class remaining(object): class remaining(object):
name = "r" name = "r"
authed = True authed = True
helptext = "Show how much is left before we are able to withdraw funds." helptext = "Show how much is left before we are able to withdraw funds."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
remaining = tx.get_remaining() remaining = tx.get_remaining()
msg(f"Remaining: {remaining}USD") msg(f"Remaining: {remaining}USD")
@ -442,7 +396,7 @@ class IRCCommands(object):
helptext = "Show how much is left before we are able to withdraw funds (including open trades)." helptext = "Show how much is left before we are able to withdraw funds (including open trades)."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
remaining = tx.get_total_remaining() remaining = tx.get_total_remaining()
msg(f"Total remaining: {remaining}USD") msg(f"Total remaining: {remaining}USD")
@ -452,7 +406,7 @@ class IRCCommands(object):
helptext = "Get total value of all open trades in USD." helptext = "Get total value of all open trades in USD."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
total = tx.get_open_trades_usd() total = tx.get_open_trades_usd()
msg(f"Total trades: {total}USD") msg(f"Total trades: {total}USD")
@ -462,7 +416,7 @@ class IRCCommands(object):
helptext = "Get total value of everything, including open trades." helptext = "Get total value of everything, including open trades."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
total = tx.get_total_with_trades() total = tx.get_total_with_trades()
msg(f"${total}") msg(f"${total}")
@ -472,7 +426,7 @@ class IRCCommands(object):
helptext = "Get total profit." helptext = "Get total profit."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
total = tx.money.get_profit() total = tx.money.get_profit()
msg(f"Profit: {total}USD") msg(f"Profit: {total}USD")
@ -482,7 +436,7 @@ class IRCCommands(object):
helptext = "Get total profit with open trades." helptext = "Get total profit with open trades."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
total = tx.money.get_profit(True) total = tx.money.get_profit(True)
msg(f"Profit: {total}USD") msg(f"Profit: {total}USD")
@ -492,6 +446,6 @@ class IRCCommands(object):
helptext = "Generate a TrueLayer signin URL." helptext = "Generate a TrueLayer signin URL."
@staticmethod @staticmethod
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify): def run(cmd, spl, length, authed, msg, agora, tx, notify):
auth_url = agora.truelayer.create_auth_url() auth_url = agora.truelayer.create_auth_url()
msg(f"Auth URL: {auth_url}") msg(f"Auth URL: {auth_url}")

View File

@ -88,7 +88,7 @@ class IRCBot(irc.IRCClient):
# Check if the command required authentication # Check if the command required authentication
if obj.authed: if obj.authed:
if host in self.admins: if host in self.admins:
obj.run(cmd, spl, length, authed, msgl, self.agora, self.revolut, self.tx, self.notify) obj.run(cmd, spl, length, authed, msgl, self.agora, self.tx, self.notify)
else: else:
# Handle authentication here instead of in the command module for security # Handle authentication here instead of in the command module for security
self.msg(channel, "Access denied.") self.msg(channel, "Access denied.")
@ -192,7 +192,8 @@ class IRCBotFactory(protocol.ClientFactory):
prcol = IRCBot(self.log) prcol = IRCBot(self.log)
self.client = prcol self.client = prcol
setattr(self.client, "agora", self.agora) setattr(self.client, "agora", self.agora)
setattr(self.client, "revolut", self.revolut) setattr(self.client, "truelayer", self.truelayer)
setattr(self.client, "nordigen", self.nordigen)
setattr(self.client, "tx", self.tx) setattr(self.client, "tx", self.tx)
setattr(self.client, "notify", self.notify) setattr(self.client, "notify", self.notify)
return prcol return prcol

View File

@ -1,247 +0,0 @@
# Twisted/Klein imports
from twisted.logger import Logger
# Other library imports
from json import dumps
from simplejson.errors import JSONDecodeError
import requests
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
import jwt
from random import choices
from string import ascii_uppercase
# Project imports
from settings import settings
class Revolut(object):
"""
Class to handle Revolut API calls.
"""
def __init__(self):
"""
Initialise the Revolut object.
Set the logger and token.
"""
self.log = Logger("revolut")
self.token = None
def setup_auth(self):
"""
Function to create a new Java Web Token and use it to get a refresh/access token.
"""
self.create_new_jwt()
self.get_access_token()
def create_new_jwt(self):
"""
Create a new Java Web Token.
"""
payload = {
"iss": settings.Revolut.Domain,
"sub": settings.Revolut.ClientID,
"aud": "https://revolut.com",
"exp": int(settings.Revolut.Expiry),
}
with open(settings.Revolut.PrivateKey, "rb") as f:
pem_bytes = f.read()
# payload = {jwt_header, jwt_body}
private_key = serialization.load_pem_private_key(pem_bytes, password=None, backend=default_backend())
encoded = jwt.encode(payload, private_key, algorithm="RS256")
settings.Revolut.JWT = encoded
settings.write()
def get_access_token(self):
"""
Get an access token with our JWT.
:return: True or False
:rtype: bool
"""
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"grant_type": "authorization_code",
"code": settings.Revolut.AuthCode,
"client_id": settings.Revolut.ClientID,
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": settings.Revolut.JWT,
}
r = requests.post(f"{settings.Revolut.Base}/auth/token", data=data, headers=headers)
try:
parsed = r.json()
except JSONDecodeError:
self.log.error("Error parsing access token response: {content}", content=r.content)
return False
if r.status_code == 200:
try:
settings.Revolut.RefreshToken = parsed["refresh_token"]
settings.Revolut.SetupToken = "0"
settings.write()
self.log.info("Refreshed refresh token - Revolut")
self.token = parsed["access_token"]
self.log.info("Refreshed access token - Revolut")
except KeyError:
self.log.error(f"Token authorization didn't contain refresh or access token: {parsed}", parsed=parsed)
return False
else:
self.log.error(f"Cannot refresh token: {parsed}", parsed=parsed)
return False
def get_new_token(self, fail=False):
"""
Get a new access token with the refresh token.
:param fail: whether to exit() if this fails
:type fail: bool
:return: True or False
:rtype: bool
"""
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"grant_type": "refresh_token",
"refresh_token": settings.Revolut.RefreshToken,
"client_id": settings.Revolut.ClientID,
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": settings.Revolut.JWT,
}
r = requests.post(f"{settings.Revolut.Base}/auth/token", data=data, headers=headers)
try:
parsed = r.json()
except JSONDecodeError:
if fail:
exit()
return False
if r.status_code == 200:
if "access_token" in parsed.keys():
self.token = parsed["access_token"]
self.log.info("Refreshed access token - Revolut")
return True
else:
self.log.error(f"Token refresh didn't contain access token: {parsed}", parsed=parsed)
if fail:
exit()
return False
else:
self.log.error(f"Cannot refresh token: {parsed}", parsed=parsed)
if fail:
exit()
return False
def setup_webhook(self):
"""
Check the webhook we have set up in Revolut.
Set up configured webhook if not already set up.
:return: True or False
:rtype: bool
"""
webhook = self.get_webhook()
if "url" in webhook.keys():
if webhook["url"] == settings.Revolut.WebhookURL:
self.log.info("Webhook exists - skipping setup: {url}", url=webhook["url"])
return True # Webhook already exists
self.log.info("Setting up webhook: {url}", url=settings.Revolut.WebhookURL)
headers = {"Authorization": f"Bearer {self.token}"}
data = {"url": settings.Revolut.WebhookURL}
r = requests.post(f"{settings.Revolut.Base}/webhook", data=dumps(data), headers=headers)
if r.status_code == 204:
self.log.info("Set up webhook: {url}", url=settings.Revolut.WebhookURL)
return True
else:
parsed = r.json()
self.log.info("Failed setting up webhook: {parsed}", parsed=parsed)
return False
def get_webhook(self):
"""
Get the webhook address active in Revolut.
:return: dict of hook with key url or False
:rtype: dict or bool
"""
headers = {"Authorization": f"Bearer {self.token}"}
r = requests.get(f"{settings.Revolut.Base}/webhook", headers=headers)
if r.status_code == 200:
parsed = r.json()
return parsed
elif r.status_code == 404:
return {}
else:
self.log.error("Cannot get webhook: {content}", r.content)
return False
def accounts(self):
"""
Get the details and balances of all Revolut accounts.
:return: account details
:rtype: dict
"""
headers = {"Authorization": f"Bearer {self.token}"}
r = requests.get(f"{settings.Revolut.Base}/accounts", headers=headers)
if r.status_code == 200:
return r.json()
else:
self.log.error("Error getting accounts: {content}", content=r.content)
return False
def get_total_usd(self):
rates = self.money.get_rates_all()
accounts = self.accounts()
if not accounts:
return False
total_usd = 0
for account in accounts:
if account["currency"] == "USD":
total_usd += account["balance"]
else:
total_usd += account["balance"] / rates[account["currency"]]
return total_usd
def convert(self, from_account_id, from_currency, to_account_id, to_currency, sell_amount):
"""
Convert currency.
:param sell_currency: currency to sell
:param buy_currency: currency to buy
:param sell_amount: amount of currency to sell
"""
reference = "".join(choices(ascii_uppercase, k=5))
headers = {"Authorization": f"Bearer {self.token}"}
data = {
"from": {
"account_id": from_account_id,
"currency": from_currency,
"amount": sell_amount,
},
"to": {
"account_id": to_account_id,
"currency": to_currency,
},
"request_id": reference,
}
r = requests.post(f"{settings.Revolut.Base}/exchange", headers=headers, data=dumps(data))
if r.status_code == 200:
return r.json()
else:
self.log.error("Error converting balance: {content}", content=r.content)
return False
def shuffle(self, currency):
"""
Exchange money in all accounts to the given currency.
:param currency: the currency to convert all our funds to
"""
accounts = self.accounts()
# Find given currency account
for account in accounts:
if account["currency"] == currency:
if account["state"] == "active" and account["public"] is True:
dest_account = account
# Remove this account
accounts.remove(dest_account)
break
for account in accounts:
if account["balance"] > 0:
self.convert(account["id"], account["currency"], dest_account["id"], dest_account["currency"], account["balance"])
return True