From a91cd270819213f5a51c6a7ae6d401a3afcfd69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Tue, 19 Dec 2023 13:15:36 -0300 Subject: [PATCH 1/7] feat: add infura rpc as fallback rpc provider for starknet --- mm-bot/.env.example | 1 + mm-bot/constants.py | 2 + mm-bot/starknet.py | 89 ++++++++++++++++++++++++++------------------- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/mm-bot/.env.example b/mm-bot/.env.example index d8c14f68..6d4e446c 100644 --- a/mm-bot/.env.example +++ b/mm-bot/.env.example @@ -1,6 +1,7 @@ ENVIRONMENT= ETH_RPC_URL= SN_RPC_URL= +SN_FALLBACK_RPC_URL= ETH_CONTRACT_ADDR= SN_CONTRACT_ADDR= ETH_PRIVATE_KEY= diff --git a/mm-bot/constants.py b/mm-bot/constants.py index 808020c7..e9c56279 100644 --- a/mm-bot/constants.py +++ b/mm-bot/constants.py @@ -8,6 +8,8 @@ ETH_RPC_URL = os.getenv('ETH_RPC_URL') SN_RPC_URL = os.getenv('SN_RPC_URL') +SN_FALLBACK_RPC_URL = os.getenv('SN_FALLBACK_RPC_URL') + ETH_CONTRACT_ADDR = os.getenv('ETH_CONTRACT_ADDR') SN_CONTRACT_ADDR = os.getenv('SN_CONTRACT_ADDR') diff --git a/mm-bot/starknet.py b/mm-bot/starknet.py index 58529902..9ccd11dd 100644 --- a/mm-bot/starknet.py +++ b/mm-bot/starknet.py @@ -1,29 +1,34 @@ import logging -import requests -import constants -import json -import os -from starknet_py.contract import Contract -from starknet_py.net.full_node_client import FullNodeClient +from starknet_py.hash.selector import get_selector_from_name from starknet_py.net.account.account import Account +from starknet_py.net.client_models import Call +from starknet_py.net.full_node_client import FullNodeClient from starknet_py.net.models.chains import StarknetChainId from starknet_py.net.signer.stark_curve_signer import KeyPair -from starknet_py.hash.selector import get_selector_from_name -from starknet_py.net.client_models import Call -from starknet_py.cairo.felt import decode_shortstring + +import constants SET_ORDER_EVENT_KEY = 0x2c75a60b5bdad73ebbf539cc807fccd09875c3cbf3f44041f852cdb96d8acd3 -full_node_client = FullNodeClient(node_url=constants.SN_RPC_URL) +main_full_node_client = FullNodeClient(node_url=constants.SN_RPC_URL) +fallback_full_node_client = FullNodeClient(node_url=constants.SN_FALLBACK_RPC_URL) +full_node_clients = [main_full_node_client, fallback_full_node_client] key_pair = KeyPair.from_private_key(key=constants.SN_PRIVATE_KEY) -account = Account( - client=full_node_client, +main_account = Account( + client=main_full_node_client, address=constants.SN_WALLET_ADDR, key_pair=key_pair, chain=StarknetChainId.TESTNET, ) +fallback_account = Account( + client=fallback_full_node_client, + address=constants.SN_WALLET_ADDR, + key_pair=key_pair, + chain=StarknetChainId.TESTNET, +) +accounts = [main_account, fallback_account] logger = logging.getLogger(__name__) @@ -35,21 +40,24 @@ def __init__(self, order_id, recipient_address, amount): self.amount = amount def __str__(self): - return f"order_id:{self.order_id}, recipent: {self.recipient_address}, amount: {self.amount}" + return f"order_id:{self.order_id}, recipient: {self.recipient_address}, amount: {self.amount}" async def get_starknet_events(): - try: - events_response = await full_node_client.get_events( - address=constants.SN_CONTRACT_ADDR, - chunk_size=10, - keys=[[SET_ORDER_EVENT_KEY]], - from_block_number='pending' - ) - except Exception as e: - logger.error(f"[-] Failed to get events: {e}") - return None - return events_response + for client in full_node_clients: + try: + events_response = await client.get_events( + address=constants.SN_CONTRACT_ADDR, + chunk_size=10, + keys=[[SET_ORDER_EVENT_KEY]], + from_block_number='pending' + ) + return events_response + except Exception as exception: + logger.error(f"[-] Failed to get events from node: {exception}") + + logger.error(f"[-] Failed to get events from all nodes") + return None async def get_is_used_order(order_id) -> bool: @@ -58,11 +66,14 @@ async def get_is_used_order(order_id) -> bool: selector=get_selector_from_name("get_order_used"), calldata=[order_id, 0], ) - try: - status = await account.client.call_contract(call) - return status[0] - except Exception as e: - return True + for account in accounts: + try: + status = await account.client.call_contract(call) + return status[0] + except Exception as exception: + logger.error(f"[-] Failed to get order status from node: {exception}") + logger.error(f"[-] Failed to get order status from all nodes") + return True async def get_latest_unfulfilled_orders(): @@ -93,11 +104,15 @@ async def withdraw(order_id, block, slot) -> bool: selector=get_selector_from_name("withdraw"), calldata=[order_id, 0, block, 0, slot_low, slot_high] ) - try: - transaction = await account.sign_invoke_transaction(call, max_fee=10000000000000) - result = await account.client.send_transaction(transaction) - await account.client.wait_for_tx(result.transaction_hash) - - logger.info(f"[+] Withdrawn from starknet: {hex(result.transaction_hash)}") - except Exception as e: - logger.error(f"[-] Failed to withdraw from starknet: {e}") + for account in accounts: + try: + transaction = await account.sign_invoke_transaction(call, max_fee=10000000000000) + result = await account.client.send_transaction(transaction) + await account.client.wait_for_tx(result.transaction_hash) + + logger.info(f"[+] Withdrawn from starknet: {hex(result.transaction_hash)}") + return True + except Exception as e: + logger.error(f"[-] Failed to withdraw from starknet: {e}") + logger.error(f"[-] Failed to withdraw from all nodes") + return False From fc7d8c9b9b9e4da6889e3dda2d37ebd8434660d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Tue, 19 Dec 2023 13:51:56 -0300 Subject: [PATCH 2/7] feat: add infura rpc as fallback rpc provider for ethereum --- mm-bot/.env.example | 1 + mm-bot/constants.py | 1 + mm-bot/ethereum.py | 58 ++++++++++++++++++++++++++++----------------- mm-bot/main.py | 3 ++- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/mm-bot/.env.example b/mm-bot/.env.example index 6d4e446c..7f06fd38 100644 --- a/mm-bot/.env.example +++ b/mm-bot/.env.example @@ -1,6 +1,7 @@ ENVIRONMENT= ETH_RPC_URL= SN_RPC_URL= +ETH_FALLBACK_RPC_URL= SN_FALLBACK_RPC_URL= ETH_CONTRACT_ADDR= SN_CONTRACT_ADDR= diff --git a/mm-bot/constants.py b/mm-bot/constants.py index e9c56279..cca8c190 100644 --- a/mm-bot/constants.py +++ b/mm-bot/constants.py @@ -8,6 +8,7 @@ ETH_RPC_URL = os.getenv('ETH_RPC_URL') SN_RPC_URL = os.getenv('SN_RPC_URL') +ETH_FALLBACK_RPC_URL = os.getenv('ETH_FALLBACK_RPC_URL') SN_FALLBACK_RPC_URL = os.getenv('SN_FALLBACK_RPC_URL') ETH_CONTRACT_ADDR = os.getenv('ETH_CONTRACT_ADDR') diff --git a/mm-bot/ethereum.py b/mm-bot/ethereum.py index 06c14a8e..b7372979 100644 --- a/mm-bot/ethereum.py +++ b/mm-bot/ethereum.py @@ -4,32 +4,46 @@ import os from web3 import Web3, AsyncWeb3 -w3 = Web3(Web3.HTTPProvider(constants.ETH_RPC_URL)) +main_w3 = Web3(Web3.HTTPProvider(constants.ETH_RPC_URL)) +fallback_w3 = Web3(Web3.HTTPProvider(constants.ETH_FALLBACK_RPC_URL)) +w3_clients = [main_w3,fallback_w3] + logger = logging.getLogger(__name__) def get_latest_block() -> int: - return w3.eth.block_number + for w3 in w3_clients: + try: + return w3.eth.block_number + except Exception as exception: + logger.error(f"[-] Failed to get block number from node: {exception}") + logger.error(f"[-] Failed to get block number from all nodes") def transfer(deposit_id, dst_addr, amount): - acct = w3.eth.account.from_key(constants.ETH_PRIVATE_KEY) - # get only the abi not the entire file - abi = json.load(open(os.path.dirname(os.path.realpath(__file__)) + '/abi/YABTransfer.json'))['abi'] - - yab_transfer = w3.eth.contract(address=constants.ETH_CONTRACT_ADDR, abi=abi) - dst_addr_bytes = int(dst_addr, 0) - deposit_id = Web3.to_int(deposit_id) - amount = Web3.to_int(amount) - # we need amount so the transaction is valid with the transfer that will be transferred - unsent_tx = yab_transfer.functions.transfer(deposit_id, dst_addr_bytes, amount).build_transaction({ - "chainId": 5, - "from": acct.address, - "nonce": w3.eth.get_transaction_count(acct.address), - "value": amount, - }) - signed_tx = w3.eth.account.sign_transaction(unsent_tx, private_key=acct.key) - - tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) - w3.eth.wait_for_transaction_receipt(tx_hash) - logger.info(f"[+] Transfer tx hash: 0x{tx_hash.hex()}") + for w3 in w3_clients: + try: + acct = w3.eth.account.from_key(constants.ETH_PRIVATE_KEY) + # get only the abi not the entire file + abi = json.load(open(os.path.dirname(os.path.realpath(__file__)) + '/abi/YABTransfer.json'))['abi'] + + yab_transfer = w3.eth.contract(address=constants.ETH_CONTRACT_ADDR, abi=abi) + dst_addr_bytes = int(dst_addr, 0) + deposit_id = Web3.to_int(deposit_id) + amount = Web3.to_int(amount) + # we need amount so the transaction is valid with the transfer that will be transferred + unsent_tx = yab_transfer.functions.transfer(deposit_id, dst_addr_bytes, amount).build_transaction({ + "chainId": 5, + "from": acct.address, + "nonce": w3.eth.get_transaction_count(acct.address), + "value": amount, + }) + signed_tx = w3.eth.account.sign_transaction(unsent_tx, private_key=acct.key) + + tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) + w3.eth.wait_for_transaction_receipt(tx_hash) + return tx_hash.hex() + except Exception as exception: + logger.error(f"[-] Failed to transfer eth on node: {exception}") + logger.error(f"[-] Failed to transfer eth on all nodes") + diff --git a/mm-bot/main.py b/mm-bot/main.py index 0d299bda..df51435f 100644 --- a/mm-bot/main.py +++ b/mm-bot/main.py @@ -55,7 +55,8 @@ async def process_order(order_id, dst_addr, amount, eth_lock): async with eth_lock: try: # in case it's processed on ethereum, but not processed on starknet - await asyncio.to_thread(ethereum.transfer, order_id, dst_addr, amount) + tx_hash_hex = await asyncio.to_thread(ethereum.transfer, order_id, dst_addr, amount) + logger.info(f"[+] Transfer tx hash: 0x{tx_hash_hex}") logger.info(f"[+] Transfer complete") except Exception as e: logger.error(f"[-] Transfer failed: {e}") From 0fa2556983e578bf989232581f0509d705df4a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Tue, 19 Dec 2023 13:56:01 -0300 Subject: [PATCH 3/7] fix: raise exception on transfer failed on all nodes --- mm-bot/ethereum.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mm-bot/ethereum.py b/mm-bot/ethereum.py index b7372979..5c15ce66 100644 --- a/mm-bot/ethereum.py +++ b/mm-bot/ethereum.py @@ -46,4 +46,5 @@ def transfer(deposit_id, dst_addr, amount): except Exception as exception: logger.error(f"[-] Failed to transfer eth on node: {exception}") logger.error(f"[-] Failed to transfer eth on all nodes") + raise Exception("Failed to transfer eth on all nodes") From 89a8d519c013181372d25448db5fab9803338ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Wed, 20 Dec 2023 11:32:36 -0300 Subject: [PATCH 4/7] refactor: separate files in folders --- mm-bot/{ => src/config}/logging_config.py | 2 +- mm-bot/{ => src}/main.py | 11 +++++------ mm-bot/{ => src/services}/ethereum.py | 7 ++++--- mm-bot/{ => src/services}/herodotus.py | 3 +-- mm-bot/{ => src/services}/starknet.py | 8 ++++---- 5 files changed, 15 insertions(+), 16 deletions(-) rename mm-bot/{ => src/config}/logging_config.py (98%) rename mm-bot/{ => src}/main.py (95%) rename mm-bot/{ => src/services}/ethereum.py (91%) rename mm-bot/{ => src/services}/herodotus.py (98%) rename mm-bot/{ => src/services}/starknet.py (95%) diff --git a/mm-bot/logging_config.py b/mm-bot/src/config/logging_config.py similarity index 98% rename from mm-bot/logging_config.py rename to mm-bot/src/config/logging_config.py index c1db4225..28ae93ae 100644 --- a/mm-bot/logging_config.py +++ b/mm-bot/src/config/logging_config.py @@ -2,7 +2,7 @@ import logging from logging.handlers import TimedRotatingFileHandler import sys -import constants +from config import constants def setup_logger(): diff --git a/mm-bot/main.py b/mm-bot/src/main.py similarity index 95% rename from mm-bot/main.py rename to mm-bot/src/main.py index df51435f..9f4b5e77 100644 --- a/mm-bot/main.py +++ b/mm-bot/src/main.py @@ -1,12 +1,11 @@ import asyncio import logging - -import ethereum -import herodotus -import json -import starknet from web3 import Web3 -from logging_config import setup_logger + +from services import ethereum +from services import herodotus +from services import starknet +from config.logging_config import setup_logger setup_logger() logger = logging.getLogger(__name__) diff --git a/mm-bot/ethereum.py b/mm-bot/src/services/ethereum.py similarity index 91% rename from mm-bot/ethereum.py rename to mm-bot/src/services/ethereum.py index 5c15ce66..7bc03e0a 100644 --- a/mm-bot/ethereum.py +++ b/mm-bot/src/services/ethereum.py @@ -1,8 +1,9 @@ import logging -import constants import json import os -from web3 import Web3, AsyncWeb3 +from web3 import Web3 + +from config import constants main_w3 = Web3(Web3.HTTPProvider(constants.ETH_RPC_URL)) fallback_w3 = Web3(Web3.HTTPProvider(constants.ETH_FALLBACK_RPC_URL)) @@ -25,7 +26,7 @@ def transfer(deposit_id, dst_addr, amount): try: acct = w3.eth.account.from_key(constants.ETH_PRIVATE_KEY) # get only the abi not the entire file - abi = json.load(open(os.path.dirname(os.path.realpath(__file__)) + '/abi/YABTransfer.json'))['abi'] + abi = json.load(open(os.getcwd() + '/abi/YABTransfer.json'))['abi'] yab_transfer = w3.eth.contract(address=constants.ETH_CONTRACT_ADDR, abi=abi) dst_addr_bytes = int(dst_addr, 0) diff --git a/mm-bot/herodotus.py b/mm-bot/src/services/herodotus.py similarity index 98% rename from mm-bot/herodotus.py rename to mm-bot/src/services/herodotus.py index 3c318562..26a36b27 100644 --- a/mm-bot/herodotus.py +++ b/mm-bot/src/services/herodotus.py @@ -1,9 +1,8 @@ import asyncio import logging -import constants import requests import time -from web3 import Web3 +from config import constants reqs = [] logger = logging.getLogger(__name__) diff --git a/mm-bot/starknet.py b/mm-bot/src/services/starknet.py similarity index 95% rename from mm-bot/starknet.py rename to mm-bot/src/services/starknet.py index 9ccd11dd..9bda6e10 100644 --- a/mm-bot/starknet.py +++ b/mm-bot/src/services/starknet.py @@ -7,7 +7,7 @@ from starknet_py.net.models.chains import StarknetChainId from starknet_py.net.signer.stark_curve_signer import KeyPair -import constants +from config import constants SET_ORDER_EVENT_KEY = 0x2c75a60b5bdad73ebbf539cc807fccd09875c3cbf3f44041f852cdb96d8acd3 @@ -76,7 +76,7 @@ async def get_is_used_order(order_id) -> bool: return True -async def get_latest_unfulfilled_orders(): +async def get_latest_unfulfilled_orders() -> set[SetOrderEvent]: request_result = await get_starknet_events() if request_result is None: return set() @@ -84,8 +84,8 @@ async def get_latest_unfulfilled_orders(): events = request_result.events orders = set() for event in events: - status = await get_is_used_order(event.data[0]) - if not status: + is_used = await get_is_used_order(event.data[0]) + if not is_used: order = SetOrderEvent( order_id=event.data[0], recipient_address=hex(event.data[2]), From c5f1ba996bb482c0d3ad22980642233b25f10e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Wed, 20 Dec 2023 11:34:49 -0300 Subject: [PATCH 5/7] refactor: separate files in folders --- mm-bot/{ => src/config}/constants.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mm-bot/{ => src/config}/constants.py (100%) diff --git a/mm-bot/constants.py b/mm-bot/src/config/constants.py similarity index 100% rename from mm-bot/constants.py rename to mm-bot/src/config/constants.py From 6e9d1f128cedb9bad55417a97fb4428a423a30d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Wed, 20 Dec 2023 11:38:53 -0300 Subject: [PATCH 6/7] chore: add TODO to gas fee administration --- mm-bot/src/services/starknet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm-bot/src/services/starknet.py b/mm-bot/src/services/starknet.py index 9bda6e10..30ec90d6 100644 --- a/mm-bot/src/services/starknet.py +++ b/mm-bot/src/services/starknet.py @@ -106,7 +106,7 @@ async def withdraw(order_id, block, slot) -> bool: ) for account in accounts: try: - transaction = await account.sign_invoke_transaction(call, max_fee=10000000000000) + transaction = await account.sign_invoke_transaction(call, max_fee=10000000000000) # TODO manage fee better result = await account.client.send_transaction(transaction) await account.client.wait_for_tx(result.transaction_hash) From 573fa29d016cfc0a1e759fe39f0c4bd9e7778aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Arce?= Date: Wed, 20 Dec 2023 23:57:27 -0300 Subject: [PATCH 7/7] fix: separate operations into methods fix: improve reliability with fallback rpc calls --- mm-bot/src/services/ethereum.py | 74 +++++++++++++++++++++++---------- mm-bot/src/services/starknet.py | 50 +++++++++++++++++----- 2 files changed, 93 insertions(+), 31 deletions(-) diff --git a/mm-bot/src/services/ethereum.py b/mm-bot/src/services/ethereum.py index 7bc03e0a..a34a2436 100644 --- a/mm-bot/src/services/ethereum.py +++ b/mm-bot/src/services/ethereum.py @@ -7,7 +7,17 @@ main_w3 = Web3(Web3.HTTPProvider(constants.ETH_RPC_URL)) fallback_w3 = Web3(Web3.HTTPProvider(constants.ETH_FALLBACK_RPC_URL)) -w3_clients = [main_w3,fallback_w3] +w3_clients = [main_w3, fallback_w3] + +main_account = main_w3.eth.account.from_key(constants.ETH_PRIVATE_KEY) +fallback_account = fallback_w3.eth.account.from_key(constants.ETH_PRIVATE_KEY) +accounts = [main_account, fallback_account] + +# get only the abi not the entire file +abi = json.load(open(os.getcwd() + '/abi/YABTransfer.json'))['abi'] +main_contract = main_w3.eth.contract(address=constants.ETH_CONTRACT_ADDR, abi=abi) +fallback_contract = fallback_w3.eth.contract(address=constants.ETH_CONTRACT_ADDR, abi=abi) +contracts = [main_contract, fallback_contract] logger = logging.getLogger(__name__) @@ -17,35 +27,57 @@ def get_latest_block() -> int: try: return w3.eth.block_number except Exception as exception: - logger.error(f"[-] Failed to get block number from node: {exception}") + logger.warning(f"[-] Failed to get block number from node: {exception}") logger.error(f"[-] Failed to get block number from all nodes") def transfer(deposit_id, dst_addr, amount): - for w3 in w3_clients: + dst_addr_bytes = int(dst_addr, 0) + deposit_id = Web3.to_int(deposit_id) + amount = Web3.to_int(amount) + + signed_tx = create_transfer(deposit_id, dst_addr_bytes, amount) + + tx_hash = send_raw_transaction(signed_tx) + wait_for_transaction_receipt(tx_hash) + return tx_hash.hex() + + +# we need amount so the transaction is valid with the transfer that will be transferred +def create_transfer(deposit_id, dst_addr_bytes, amount): + for index, w3 in enumerate(w3_clients): try: - acct = w3.eth.account.from_key(constants.ETH_PRIVATE_KEY) - # get only the abi not the entire file - abi = json.load(open(os.getcwd() + '/abi/YABTransfer.json'))['abi'] - - yab_transfer = w3.eth.contract(address=constants.ETH_CONTRACT_ADDR, abi=abi) - dst_addr_bytes = int(dst_addr, 0) - deposit_id = Web3.to_int(deposit_id) - amount = Web3.to_int(amount) - # we need amount so the transaction is valid with the transfer that will be transferred - unsent_tx = yab_transfer.functions.transfer(deposit_id, dst_addr_bytes, amount).build_transaction({ + unsent_tx = contracts[index].functions.transfer(deposit_id, dst_addr_bytes, amount).build_transaction({ "chainId": 5, - "from": acct.address, - "nonce": w3.eth.get_transaction_count(acct.address), + "from": accounts[index].address, + "nonce": w3.eth.get_transaction_count(accounts[index].address), "value": amount, }) - signed_tx = w3.eth.account.sign_transaction(unsent_tx, private_key=acct.key) + signed_tx = w3.eth.account.sign_transaction(unsent_tx, private_key=accounts[index].key) + return signed_tx + except Exception as exception: + logger.warning(f"[-] Failed to create transfer eth on node: {exception}") + logger.error(f"[-] Failed to create transfer eth on all nodes") + raise Exception("Failed to create transfer eth on all nodes") + +def send_raw_transaction(signed_tx): + for w3 in w3_clients: + try: tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) - w3.eth.wait_for_transaction_receipt(tx_hash) - return tx_hash.hex() + return tx_hash except Exception as exception: - logger.error(f"[-] Failed to transfer eth on node: {exception}") - logger.error(f"[-] Failed to transfer eth on all nodes") - raise Exception("Failed to transfer eth on all nodes") + logger.warning(f"[-] Failed to send raw transaction on node: {exception}") + logger.error(f"[-] Failed to send raw transaction on all nodes") + raise Exception("Failed to send raw transaction on all nodes") + +def wait_for_transaction_receipt(tx_hash): + for w3 in w3_clients: + try: + w3.eth.wait_for_transaction_receipt(tx_hash) + return True + except Exception as exception: + logger.warning(f"[-] Failed to wait for transaction receipt on node: {exception}") + logger.error(f"[-] Failed to wait for transaction receipt on all nodes") + raise Exception("Failed to wait for transaction receipt on all nodes") diff --git a/mm-bot/src/services/starknet.py b/mm-bot/src/services/starknet.py index 30ec90d6..0d4b787e 100644 --- a/mm-bot/src/services/starknet.py +++ b/mm-bot/src/services/starknet.py @@ -54,8 +54,7 @@ async def get_starknet_events(): ) return events_response except Exception as exception: - logger.error(f"[-] Failed to get events from node: {exception}") - + logger.warning(f"[-] Failed to get events from node: {exception}") logger.error(f"[-] Failed to get events from all nodes") return None @@ -71,7 +70,7 @@ async def get_is_used_order(order_id) -> bool: status = await account.client.call_contract(call) return status[0] except Exception as exception: - logger.error(f"[-] Failed to get order status from node: {exception}") + logger.warning(f"[-] Failed to get order status from node: {exception}") logger.error(f"[-] Failed to get order status from all nodes") return True @@ -104,15 +103,46 @@ async def withdraw(order_id, block, slot) -> bool: selector=get_selector_from_name("withdraw"), calldata=[order_id, 0, block, 0, slot_low, slot_high] ) + try: + transaction = await sign_invoke_transaction(call, max_fee=10000000000000) # TODO manage fee better + result = await send_transaction(transaction) + await wait_for_tx(result.transaction_hash) + + logger.info(f"[+] Withdrawn from starknet: {hex(result.transaction_hash)}") + return True + except Exception as e: + logger.error(f"[-] Failed to withdraw from starknet: {e}") + return False + + +async def sign_invoke_transaction(call: Call, max_fee: int): + for account in accounts: + try: + transaction = await account.sign_invoke_transaction(call, max_fee=max_fee) + return transaction + except Exception as e: + logger.warning(f"[-] Failed to sign invoke transaction: {e}") + logger.error(f"[-] Failed to sign invoke transaction from all nodes") + raise Exception("Failed to sign invoke transaction from all nodes") + + +async def send_transaction(transaction): for account in accounts: try: - transaction = await account.sign_invoke_transaction(call, max_fee=10000000000000) # TODO manage fee better result = await account.client.send_transaction(transaction) - await account.client.wait_for_tx(result.transaction_hash) + return result + except Exception as e: + logger.warning(f"[-] Failed to send transaction: {e}") + logger.error(f"[-] Failed to send transaction from all nodes") + raise Exception("Failed to send transaction from all nodes") + - logger.info(f"[+] Withdrawn from starknet: {hex(result.transaction_hash)}") - return True +async def wait_for_tx(transaction_hash): + for account in accounts: + try: + await account.client.wait_for_tx(transaction_hash) + return except Exception as e: - logger.error(f"[-] Failed to withdraw from starknet: {e}") - logger.error(f"[-] Failed to withdraw from all nodes") - return False + logger.warning(f"[-] Failed to wait for tx: {e}") + logger.error(f"[-] Failed to wait for tx from all nodes") + raise Exception("Failed to wait for tx from all nodes")