Skip to content

Commit

Permalink
Merge pull request #692 from mraniki/dev
Browse files Browse the repository at this point in the history
💥 Refactoring (ContractUtils, AccountUtils and new TokenUtils)
  • Loading branch information
mraniki authored Jul 14, 2024
2 parents f17dc49 + a092f24 commit 5904692
Show file tree
Hide file tree
Showing 15 changed files with 528 additions and 437 deletions.
72 changes: 72 additions & 0 deletions dxsp/default_settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,22 @@ mapping = [ # mapping to use to change instrument per exchange
{ id = "BTC", alt = "WBTC" ,enable = true },
]
rotki_report_endpoint= "http://localhost:5042/api/v1/reports/1"
# Header to use for retrieving urls content below
headers = {User-Agent= 'Mozilla/5.0'}

# DEX ABI to use in case you have no explorer setup
abi_url = "https://raw.githubusercontent.com/Uniswap/interface/44c355c7f0f8ab5bdb3e0790560e84e59f5666f7/src/abis/erc20.json"

# token list using uniswap tokenlist format
# https://github.com/mraniki/tokenlist
# this can be used to avoid using coingecko
# or be used for niche token not listed anywhere
# or for testnet
# token_mainnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/all.json"
# token_testnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/testnet.json"
token_mainnet_list = ""
token_testnet_list = ""
token_personal_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/TT.json"

# # uniswap v2 protocol type and router uniswap
# [default.dex.eth]
Expand All @@ -87,6 +102,21 @@ rotki_report_endpoint= "http://localhost:5042/api/v1/reports/1"
# { id = "BTC", alt = "WBTC" },
# ]
# rotki_report_endpoint= "http://localhost:5042/api/1/pnl"
# Header to use for retrieving urls content below
# headers = {User-Agent= 'Mozilla/5.0'}

# # DEX ABI to use in case you have no explorer setup
# abi_url = "https://raw.githubusercontent.com/Uniswap/interface/44c355c7f0f8ab5bdb3e0790560e84e59f5666f7/src/abis/erc20.json"

# # token list using uniswap tokenlist format
# # https://github.com/mraniki/tokenlist
# # this can be used to avoid using coingecko
# # or be used for niche token not listed anywhere
# # or for testnet
# # token_mainnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/all.json"
# # token_testnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/testnet.json"
# token_personal_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/TT.json"


# # uniswap v2 protocol type and router pancakeswap on BSC chain 56
# [default.dex.bsc]
Expand All @@ -112,6 +142,20 @@ rotki_report_endpoint= "http://localhost:5042/api/v1/reports/1"
# { id = "BTC", alt = "BTCB" },
# ]
# rotki_report_endpoint= "http://localhost:5042/api/1/pnl"
# headers = {User-Agent= 'Mozilla/5.0'}

# # DEX ABI to use in case you have no explorer setup
# abi_url = "https://raw.githubusercontent.com/Uniswap/interface/44c355c7f0f8ab5bdb3e0790560e84e59f5666f7/src/abis/erc20.json"

# # token list using uniswap tokenlist format
# # https://github.com/mraniki/tokenlist
# # this can be used to avoid using coingecko
# # or be used for niche token not listed anywhere
# # or for testnet
# # token_mainnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/all.json"
# # token_testnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/testnet.json"
# token_personal_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/TT.json"


# # ZeroX 0x protocol type on polygon chain 137
# [default.dex.polygon]
Expand All @@ -137,6 +181,20 @@ rotki_report_endpoint= "http://localhost:5042/api/v1/reports/1"
# { id = "BTC", alt = "WBTC" },
# ]
# rotki_report_endpoint= "http://localhost:5042/api/1/pnl"
# headers = {User-Agent= 'Mozilla/5.0'}

# # DEX ABI to use in case you have no explorer setup
# abi_url = "https://raw.githubusercontent.com/Uniswap/interface/44c355c7f0f8ab5bdb3e0790560e84e59f5666f7/src/abis/erc20.json"

# # token list using uniswap tokenlist format
# # https://github.com/mraniki/tokenlist
# # this can be used to avoid using coingecko
# # or be used for niche token not listed anywhere
# # or for testnet
# # token_mainnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/all.json"
# # token_testnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/testnet.json"
# token_personal_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/TT.json"


# # kwenta protocol type on OPTIMISM chain 10
# [default.dex.opt]
Expand Down Expand Up @@ -164,6 +222,20 @@ rotki_report_endpoint= "http://localhost:5042/api/v1/reports/1"
# { id = "BTC", alt = "BTC" },
# ]
# rotki_report_endpoint= "http://localhost:5042/api/1/pnl"
# headers = {User-Agent= 'Mozilla/5.0'}

# # DEX ABI to use in case you have no explorer setup
# abi_url = "https://raw.githubusercontent.com/Uniswap/interface/44c355c7f0f8ab5bdb3e0790560e84e59f5666f7/src/abis/erc20.json"

# # token list using uniswap tokenlist format
# # https://github.com/mraniki/tokenlist
# # this can be used to avoid using coingecko
# # or be used for niche token not listed anywhere
# # or for testnet
# # token_mainnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/all.json"
# # token_testnet_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/testnet.json"
# # token_personal_list = "https://raw.githubusercontent.com/mraniki/tokenlist/main/TT.json"


########################################
### END OF DEFAULT SETTINGS ###
Expand Down
96 changes: 58 additions & 38 deletions dxsp/handler/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import aiohttp
from loguru import logger
from web3 import Web3

# from web3.exceptions import Web3Exception
from web3.gas_strategies.time_based import medium_gas_price_strategy
from web3.middleware import geth_poa_middleware

Expand Down Expand Up @@ -73,30 +75,42 @@ def __init__(self, **kwargs):
Returns:
None
"""
self.name = kwargs.get("name", None)
get = kwargs.get
self.name = get("name", None)
logger.debug(f"Setting up: {self.name}")

self.protocol = kwargs.get("protocol") or "uniswap"
self.protocol_version = kwargs.get("protocol_version") or 2
self.api_endpoint = kwargs.get("api_endpoint", None)
self.api_key = kwargs.get("api_key", None)
self.rpc = kwargs.get("rpc", None)
self.w3 = kwargs.get("w3", None)
self.wallet_address = kwargs.get("wallet_address", None)
self.private_key = kwargs.get("private_key", None)
self.router_contract_addr = kwargs.get("router_contract_addr", None)
self.factory_contract_addr = kwargs.get("factory_contract_addr", None)
self.trading_asset_address = kwargs.get("trading_asset_address", None)
self.trading_risk_percentage = kwargs.get("trading_risk_percentage", None)
self.trading_asset_separator = kwargs.get("trading_asset_separator", None)
self.trading_risk_amount = kwargs.get("trading_risk_amount", None)
self.trading_slippage = kwargs.get("trading_slippage", None)
self.trading_amount_threshold = kwargs.get("trading_amount_threshold", None)
self.block_explorer_url = kwargs.get("block_explorer_url", None)
self.block_explorer_api = kwargs.get("block_explorer_api", None)
self.mapping = kwargs.get("mapping", None)
self.is_pnl_active = kwargs.get("is_pnl_active", False)
self.rotki_report_endpoint = kwargs.get("rotki_report_endpoint", None)
self.protocol = get("library") or get("protocol") or "uniswap"
self.protocol_version = get("protocol_version", 2)
self.api_endpoint = get("api_endpoint", None)
self.api_key = get("api_key", None)
self.rpc = get("rpc", None)
self.w3 = get("w3", None)
self.wallet_address = get("wallet_address", None)
self.private_key = get("private_key", None)
self.headers = get("headers", "{User-Agent= 'Mozilla/5.0'}")
self.abi_url = get(
"abi_url",
"https://raw.githubusercontent.com/Uniswap/interface/44c355c7f0f8ab5bdb3e0790560e84e59f5666f7/src/abis/erc20.json",
)
self.token_mainnet_list = get("token_mainnet_list", None)
self.token_testnet_list = get("token_testnet_list", None)
self.token_personal_list = get("token_personal_list", None)
self.router_contract_addr = get("router_contract_addr", None)
self.factory_contract_addr = get("factory_contract_addr", None)
self.trading_asset_address = get("trading_asset_address", None)
self.trading_risk_percentage = get("trading_risk_percentage", None)
self.trading_asset_separator = get("trading_asset_separator", None)
self.trading_risk_amount = get("trading_risk_amount", None)
self.trading_slippage = get("trading_slippage", None)
self.trading_amount_threshold = get("trading_amount_threshold", None)
self.block_explorer_url = get("block_explorer_url", None)
self.block_explorer_api = get("block_explorer_api", None)
self.mapping = get("mapping", None)
self.is_pnl_active = get("is_pnl_active", False)
self.rotki_report_endpoint = get("rotki_report_endpoint", None)
self.client = None
self.chain = None
self.account_number = None
if self.rpc:
try:
self.w3 = Web3(Web3.HTTPProvider(self.rpc))
Expand All @@ -106,29 +120,34 @@ def __init__(self, **kwargs):
f"Chain {self.w3.net.version} - {int(self.w3.net.version, 16)}"
)
except Exception as e:
logger.error(f"Failed to connect to RPC: {e}")
# This block catches all other exceptions
logger.error(f"Invalid RPC URL or response: {e}")
self.w3 = None

if self.w3 and self.wallet_address:
self.account_number = (
f"{int(self.w3.net.version, 16)} - {str(self.wallet_address)[-8:]}"
)
self.chain = self.w3.net.version
self.account_number = f"{self.chain} - {str(self.wallet_address)[-8:]}"
logger.debug("Account {}", self.account_number)
self.contract_utils = ContractUtils(
self.w3, self.block_explorer_url, self.block_explorer_api
w3=self.w3,
abi_url=self.abi_url,
token_mainnet_list=self.token_mainnet_list,
token_testnet_list=self.token_testnet_list,
token_personal_list=self.token_personal_list,
headers=self.headers,
block_explorer_url=self.block_explorer_url,
block_explorer_api=self.block_explorer_api,
)
self.account = AccountUtils(
self.w3,
self.contract_utils,
self.wallet_address,
self.private_key,
self.trading_asset_address,
self.block_explorer_url,
self.block_explorer_api,
w3=self.w3,
contract_utils=self.contract_utils,
wallet_address=self.wallet_address,
private_key=self.private_key,
trading_asset_address=self.trading_asset_address,
router_contract_addr=self.router_contract_addr,
block_explorer_url=self.block_explorer_url,
block_explorer_api=self.block_explorer_api,
)
else:
self.account_number = None

self.client = None

async def resolve_token(self, **kwargs):
"""
Expand Down Expand Up @@ -397,6 +416,7 @@ async def calculate_pnl(self, period=None):
Returns:
pnl: The calculated PnL value.
"""

if self.rotki_report_endpoint is None:
return 0
params = {"period": period} if period else {}
Expand Down
29 changes: 9 additions & 20 deletions dxsp/handler/kwenta.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def __init__(
"""
super().__init__(**kwargs)
if self.rpc is None or self.w3 is None:
return
self.client = Kwenta(
network_id=int(self.w3.net.version),
provider_rpc=self.rpc,
Expand Down Expand Up @@ -59,39 +61,26 @@ async def get_quote(
Exception: If an error occurs during the retrieval process.
"""
try:
logger.debug(
"Kwenta get_quote {} {} {} {}",
buy_address,
buy_symbol,
sell_address,
sell_symbol,
)
# Resolve buy_token
buy_token = await self.resolve_token(
address_or_symbol=buy_address
or buy_symbol
or self.trading_asset_address
)

# Resolve sell_token
sell_token = await self.resolve_token(
address_or_symbol=sell_address or sell_symbol
)
logger.info("buy_token: {}", buy_token)
logger.info("sell_token: {}", sell_token)
if not buy_token:
return "Buy token not found"
if not sell_token:
return "Sell token not found"

if not buy_token or not sell_token:
return "⚠️ Buy or sell token not found"

market = self.client.markets[f"{sell_token.symbol}"]
logger.info("market: {}", market)

quote = self.client.get_current_asset_price(sell_token.symbol)
logger.info("quote: {}", quote)
return quote
return quote or "⚠️ Quote failed"
except Exception as error:
logger.error("Kwenta Quote failed {}, Verify Kwenta wallet setup", error)
logger.debug(error)
logger.error("Quote failed {}", error)
return f"⚠️ {error}"

async def make_swap(self, sell_address, buy_address, amount):
pass
Expand Down
12 changes: 4 additions & 8 deletions dxsp/handler/uniswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(
"""
super().__init__(**kwargs)
if self.rpc is None:
if self.rpc is None or self.w3 is None:
return
self.build_client()

Expand All @@ -42,9 +42,8 @@ def build_client(self):
"""
try:
logger.debug(
"Uniswap client starting. RPC: {}, Wallet: {}",
"Uniswap client starting. RPC: {}",
self.rpc,
self.wallet_address,
)
self.client = Uniswap(
address=self.wallet_address,
Expand All @@ -54,7 +53,6 @@ def build_client(self):
web3=self.w3,
factory_contract_addr=self.factory_contract_addr,
router_contract_addr=self.router_contract_addr,
# enable_caching=True,
)
logger.debug("Uniswap client {}", self.client)
except Exception as error:
Expand Down Expand Up @@ -103,10 +101,8 @@ async def get_quote(
)
logger.debug("Buy token {}. Sell token {}", buy_token, sell_token)

if not buy_token:
return "Buy token not found"
if not sell_token:
return "Sell token not found"
if not buy_token or not sell_token:
return "⚠️ Buy or sell token not found"
amount_wei = amount * (10 ** (sell_token.decimals))

logger.debug(
Expand Down
21 changes: 12 additions & 9 deletions dxsp/handler/zerox.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def __init__(
"""
super().__init__(**kwargs)
# self.build_client()
self.client = "0x"

async def get_quote(
Expand Down Expand Up @@ -68,10 +67,8 @@ async def get_quote(
sell_token = await self.resolve_token(
address_or_symbol=sell_address or sell_symbol
)
if not buy_token:
return "Buy token not found"
if not sell_token:
return "Sell token not found"
if not buy_token or not sell_token:
return "⚠️ Buy or sell token not found"
amount_wei = amount * (10 ** (sell_token.decimals))

url = (
Expand All @@ -90,6 +87,7 @@ async def get_quote(
return response["code"], response["reason"]
except Exception as error:
logger.error("Quote failed {}", error)
return f"⚠️ {error}"

async def make_swap(self, buy_address, sell_address, amount):
"""
Expand All @@ -108,7 +106,12 @@ async def make_swap(self, buy_address, sell_address, amount):
of the `account` object with the `swap_order`
as an argument.
"""
logger.debug(f"0x make_swap {buy_address} {sell_address} {amount}")
swap_order = await self.get_quote(buy_address, sell_address, amount)
if swap_order:
return await self.account.get_sign(swap_order)
try:
logger.debug(f"0x make_swap {buy_address} {sell_address} {amount}")
swap_order = await self.get_quote(buy_address, sell_address, amount)
if swap_order:
return await self.account.get_sign(swap_order)

except Exception as error:
logger.error("Swap failed {}", error)
return f"⚠️ {error}"
Loading

0 comments on commit 5904692

Please sign in to comment.