From fb570b0854e19e2177730b008ef122a1b3d45e66 Mon Sep 17 00:00:00 2001 From: Judah <109892550+Judah04@users.noreply.github.com> Date: Mon, 16 Dec 2024 06:38:43 +0000 Subject: [PATCH 1/3] add withdraw all contract --- web_app/api/user.py | 34 +++++++++++++++++++++++ web_app/contract_tools/blockchain_call.py | 33 ++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/web_app/api/user.py b/web_app/api/user.py index 0434a4f6..dd1c0ce3 100644 --- a/web_app/api/user.py +++ b/web_app/api/user.py @@ -1,3 +1,4 @@ + """ This module handles user-related API endpoints. """ @@ -21,6 +22,7 @@ TelegramUserDBConnector, UserDBConnector, ) +from web_app.contract_tools.blockchain_call import CLIENT logger = logging.getLogger(__name__) router = APIRouter() # Initialize the router @@ -298,3 +300,35 @@ async def allow_notification( raise HTTPException(status_code=404, detail=str(e)) except Exception as e: raise HTTPException(status_code=500, detail="Internal server error") + + +@router.post( + "/api/withdraw-all", + tags=["User Operations"], + summary="Withdraw all tokens from user's contract", + response_description="Status of withdrawal operations", +) +async def withdraw_all(wallet_id: str) -> dict: + """ + Withdraws all supported tokens from the user's contract. + + :param wallet_id: The wallet ID of the user. + :return: detail: "Successfully initiated withdrawals for all tokens" + """ + try: + # Get user's contract address + contract_address = await get_user_contract(wallet_id) + if not contract_address: + raise HTTPException(status_code=404, detail="Contract not found") + + # Perform withdrawals + await CLIENT.withdraw_all(contract_address) + + return {"detail": "Successfully initiated withdrawals for all tokens"} + + except Exception as e: + logger.error(f"Error in withdraw_all: {e}") + raise HTTPException( + status_code=500, + detail=f"Failed to withdraw tokens: {str(e)}" + ) diff --git a/web_app/contract_tools/blockchain_call.py b/web_app/contract_tools/blockchain_call.py index 7704e741..cc10d1a0 100644 --- a/web_app/contract_tools/blockchain_call.py +++ b/web_app/contract_tools/blockchain_call.py @@ -352,5 +352,38 @@ async def add_extra_deposit(self, contract_address: str, token_address: str, amo calldata=[self._convert_address(token_address), amount], ) + async def withdraw_all(self, contract_address: str) -> List[Any]: + """ + Withdraws all supported tokens from the contract by calling withdraw with amount=0. + + :param contract_address: The contract address to withdraw from + :return: List of responses from withdraw calls. Failed withdrawals return None. + """ + contract_addr_int = self._convert_address(contract_address) + tasks = [] + + for token in TokenParams.tokens(): + try: + token_addr_int = self._convert_address(token.address) + tasks.append( + self._func_call( + addr=contract_addr_int, + selector="withdraw", + calldata=[token_addr_int, 0] + ) + ) + except Exception as e: + logger.error(f"Error preparing withdrawal for token {token.address}: {str(e)}") + + results = [] + try: + results = await asyncio.gather(*tasks, return_exceptions=True) + + results = [None if isinstance(r, Exception) else r for r in results] + except Exception as e: + logger.error(f"Error during batch withdrawal execution: {str(e)}") + + return results + CLIENT = StarknetClient() From 043a9fc658a8edd4246387c94c76e524ce9d63c6 Mon Sep 17 00:00:00 2001 From: Judah <109892550+Judah04@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:48:38 +0000 Subject: [PATCH 2/3] fix review --- web_app/api/user.py | 47 ++++++++++++----------- web_app/contract_tools/blockchain_call.py | 41 ++++++++++---------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/web_app/api/user.py b/web_app/api/user.py index dd1c0ce3..e7f7cfeb 100644 --- a/web_app/api/user.py +++ b/web_app/api/user.py @@ -309,26 +309,27 @@ async def allow_notification( response_description="Status of withdrawal operations", ) async def withdraw_all(wallet_id: str) -> dict: - """ - Withdraws all supported tokens from the user's contract. - - :param wallet_id: The wallet ID of the user. - :return: detail: "Successfully initiated withdrawals for all tokens" - """ - try: - # Get user's contract address - contract_address = await get_user_contract(wallet_id) - if not contract_address: - raise HTTPException(status_code=404, detail="Contract not found") - - # Perform withdrawals - await CLIENT.withdraw_all(contract_address) - - return {"detail": "Successfully initiated withdrawals for all tokens"} - - except Exception as e: - logger.error(f"Error in withdraw_all: {e}") - raise HTTPException( - status_code=500, - detail=f"Failed to withdraw tokens: {str(e)}" - ) + """ + Withdraws all supported tokens from the user's contract. + + :param wallet_id: The wallet ID of the user. + :return: detail: "Successfully initiated withdrawals for all tokens" + """ + # Get user's contract address + contract_address = await get_user_contract(wallet_id) + if not contract_address: + raise HTTPException(status_code=404, detail="Contract not found") + + try: + # Perform withdrawals + results = await CLIENT.withdraw_all(contract_address) + return { + "detail": "Successfully initiated withdrawals for all tokens", + "results": results + } + except Exception as e: + logger.error(f"Contract withdrawal failed: {str(e)}") + raise HTTPException( + status_code=500, + detail=f"Failed to withdraw tokens: {str(e)}" + ) diff --git a/web_app/contract_tools/blockchain_call.py b/web_app/contract_tools/blockchain_call.py index cc10d1a0..28a5d650 100644 --- a/web_app/contract_tools/blockchain_call.py +++ b/web_app/contract_tools/blockchain_call.py @@ -352,37 +352,36 @@ async def add_extra_deposit(self, contract_address: str, token_address: str, amo calldata=[self._convert_address(token_address), amount], ) - async def withdraw_all(self, contract_address: str) -> List[Any]: + async def withdraw_all(self, contract_address: str) -> dict[str, str]: """ Withdraws all supported tokens from the contract by calling withdraw with amount=0. :param contract_address: The contract address to withdraw from - :return: List of responses from withdraw calls. Failed withdrawals return None. + :return: A dictionary summarizing the results for each token. """ contract_addr_int = self._convert_address(contract_address) - tasks = [] - - for token in TokenParams.tokens(): + results = {} + + for token in TokenParams.tokens(): try: - token_addr_int = self._convert_address(token.address) - tasks.append( - self._func_call( - addr=contract_addr_int, - selector="withdraw", - calldata=[token_addr_int, 0] - ) + token_addr_int = self._convert_address(token.address) + token_symbol = token.name + logger.info(f"Withdrawing {token_symbol} from contract {contract_address}") + await self._func_call( + addr=contract_addr_int, + selector="withdraw", + calldata=[token_addr_int, 0] ) + results[token_symbol] = "Success" + + except ValueError as e: + logger.error(f"Invalid address format for {token_symbol}: {str(e)}") + results[token_symbol] = f"Failed: Invalid address format" + except Exception as e: - logger.error(f"Error preparing withdrawal for token {token.address}: {str(e)}") - - results = [] - try: - results = await asyncio.gather(*tasks, return_exceptions=True) + logger.error(f"Error withdrawing {token_symbol}: {e}") + results[token_symbol] = f"Failed: {e}" - results = [None if isinstance(r, Exception) else r for r in results] - except Exception as e: - logger.error(f"Error during batch withdrawal execution: {str(e)}") - return results From 50737667ab5bb32867b3bf4f8a35d8336ea426b4 Mon Sep 17 00:00:00 2001 From: Judah <109892550+Judah04@users.noreply.github.com> Date: Tue, 17 Dec 2024 04:25:02 +0000 Subject: [PATCH 3/3] fix review --- web_app/api/user.py | 33 +++++++++-------------- web_app/contract_tools/blockchain_call.py | 17 +++++++----- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/web_app/api/user.py b/web_app/api/user.py index e7f7cfeb..77cb4b20 100644 --- a/web_app/api/user.py +++ b/web_app/api/user.py @@ -309,27 +309,20 @@ async def allow_notification( response_description="Status of withdrawal operations", ) async def withdraw_all(wallet_id: str) -> dict: - """ - Withdraws all supported tokens from the user's contract. - - :param wallet_id: The wallet ID of the user. - :return: detail: "Successfully initiated withdrawals for all tokens" - """ - # Get user's contract address - contract_address = await get_user_contract(wallet_id) - if not contract_address: + """ + Withdraws all supported tokens from the user's contract. + + :param wallet_id: The wallet ID of the user. + :return: detail: "Successfully initiated withdrawals for all tokens" + """ + # Get user's contract address + contract_address = user_db.get_contract_address_by_wallet_id(wallet_id) + if not contract_address: raise HTTPException(status_code=404, detail="Contract not found") - try: - # Perform withdrawals - results = await CLIENT.withdraw_all(contract_address) - return { + # Perform withdrawals + results = await CLIENT.withdraw_all(contract_address) + return { "detail": "Successfully initiated withdrawals for all tokens", "results": results - } - except Exception as e: - logger.error(f"Contract withdrawal failed: {str(e)}") - raise HTTPException( - status_code=500, - detail=f"Failed to withdraw tokens: {str(e)}" - ) + } diff --git a/web_app/contract_tools/blockchain_call.py b/web_app/contract_tools/blockchain_call.py index 28a5d650..c7f6eb83 100644 --- a/web_app/contract_tools/blockchain_call.py +++ b/web_app/contract_tools/blockchain_call.py @@ -362,10 +362,18 @@ async def withdraw_all(self, contract_address: str) -> dict[str, str]: contract_addr_int = self._convert_address(contract_address) results = {} - for token in TokenParams.tokens(): + for token in TokenParams.tokens(): + token_symbol = token.name + try: token_addr_int = self._convert_address(token.address) - token_symbol = token.name + + except ValueError as e: + logger.error(f"Invalid address format for {token_symbol}: {str(e)}") + results[token_symbol] = f"Failed: Invalid address format" + continue + + try: logger.info(f"Withdrawing {token_symbol} from contract {contract_address}") await self._func_call( addr=contract_addr_int, @@ -373,11 +381,6 @@ async def withdraw_all(self, contract_address: str) -> dict[str, str]: calldata=[token_addr_int, 0] ) results[token_symbol] = "Success" - - except ValueError as e: - logger.error(f"Invalid address format for {token_symbol}: {str(e)}") - results[token_symbol] = f"Failed: Invalid address format" - except Exception as e: logger.error(f"Error withdrawing {token_symbol}: {e}") results[token_symbol] = f"Failed: {e}"