From 78f27553805f7bcb58e74ab3b89bf666c4b22d5b Mon Sep 17 00:00:00 2001 From: John Peterson <98187317+John-peterson-coinbase@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:46:41 -0500 Subject: [PATCH] Revert "feat(PSDK-854): Morpho Vault Deposit/Withdraw Actions (#111)" (#117) This reverts commit f0f1bd56e445dc0bc8c1dfc8b1f171c1d159185b. --- cdp-agentkit-core/python/CHANGELOG.md | 5 - .../cdp_agentkit_core/actions/__init__.py | 4 - .../actions/morpho/__init__.py | 0 .../actions/morpho/constants.py | 40 ----- .../actions/morpho/deposit.py | 88 --------- .../cdp_agentkit_core/actions/morpho/utils.py | 35 ---- .../actions/morpho/withdraw.py | 67 ------- .../tests/actions/morpho/test_deposit.py | 167 ------------------ .../tests/actions/morpho/test_withdraw.py | 92 ---------- .../python/tests/factories/asset_factory.py | 17 -- 10 files changed, 515 deletions(-) delete mode 100644 cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/__init__.py delete mode 100644 cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/constants.py delete mode 100644 cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/deposit.py delete mode 100644 cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/utils.py delete mode 100644 cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/withdraw.py delete mode 100644 cdp-agentkit-core/python/tests/actions/morpho/test_deposit.py delete mode 100644 cdp-agentkit-core/python/tests/actions/morpho/test_withdraw.py delete mode 100644 cdp-agentkit-core/python/tests/factories/asset_factory.py diff --git a/cdp-agentkit-core/python/CHANGELOG.md b/cdp-agentkit-core/python/CHANGELOG.md index 7e1faf530..fdbca6752 100644 --- a/cdp-agentkit-core/python/CHANGELOG.md +++ b/cdp-agentkit-core/python/CHANGELOG.md @@ -2,11 +2,6 @@ ## Unreleased -### Added - -- Added `morpho_deposit` action to deposit to Morpho Vault. -- Added `morpho_withdrawal` action to withdraw from Morpho Vault. - ## [0.0.8] - 2025-01-13 ### Added diff --git a/cdp-agentkit-core/python/cdp_agentkit_core/actions/__init__.py b/cdp-agentkit-core/python/cdp_agentkit_core/actions/__init__.py index 83a6772fd..b07f1d849 100644 --- a/cdp-agentkit-core/python/cdp_agentkit_core/actions/__init__.py +++ b/cdp-agentkit-core/python/cdp_agentkit_core/actions/__init__.py @@ -4,8 +4,6 @@ from cdp_agentkit_core.actions.get_balance import GetBalanceAction from cdp_agentkit_core.actions.get_wallet_details import GetWalletDetailsAction from cdp_agentkit_core.actions.mint_nft import MintNftAction -from cdp_agentkit_core.actions.morpho.deposit import MorphoDepositAction -from cdp_agentkit_core.actions.morpho.withdraw import MorphoWithdrawAction from cdp_agentkit_core.actions.register_basename import RegisterBasenameAction from cdp_agentkit_core.actions.request_faucet_funds import RequestFaucetFundsAction from cdp_agentkit_core.actions.trade import TradeAction @@ -44,6 +42,4 @@ def get_all_cdp_actions() -> list[type[CdpAction]]: "WowCreateTokenAction", "WowSellTokenAction", "WrapEthAction", - "MorphoDepositAction", - "MorphoWithdrawAction", ] diff --git a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/__init__.py b/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/constants.py b/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/constants.py deleted file mode 100644 index 65733d4a5..000000000 --- a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/constants.py +++ /dev/null @@ -1,40 +0,0 @@ -MORPHO_BASE_ADDRESS = "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb" - -ERC20_APPROVE_ABI = [ - { - "constant": False, - "inputs": [ - {"internalType": "address", "name": "spender", "type": "address"}, - {"internalType": "uint256", "name": "value", "type": "uint256"}, - ], - "name": "approve", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "payable": False, - "stateMutability": "nonpayable", - "type": "function", - }, -] - -METAMORPHO_ABI = [ - { - "inputs": [ - {"internalType": "uint256", "name": "assets", "type": "uint256"}, - {"internalType": "address", "name": "receiver", "type": "address"}, - ], - "name": "deposit", - "outputs": [{"internalType": "uint256", "name": "shares", "type": "uint256"}], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "assets", "type": "uint256"}, - {"internalType": "address", "name": "receiver", "type": "address"}, - {"internalType": "address", "name": "owner", "type": "address"}, - ], - "name": "withdraw", - "outputs": [{"internalType": "uint256", "name": "shares", "type": "uint256"}], - "stateMutability": "nonpayable", - "type": "function", - }, -] diff --git a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/deposit.py b/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/deposit.py deleted file mode 100644 index 5cdda1001..000000000 --- a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/deposit.py +++ /dev/null @@ -1,88 +0,0 @@ -from collections.abc import Callable -from decimal import Decimal - -from cdp import Asset, Wallet -from pydantic import BaseModel - -from cdp_agentkit_core.actions import CdpAction -from cdp_agentkit_core.actions.morpho.constants import METAMORPHO_ABI -from cdp_agentkit_core.actions.morpho.utils import approve - - -class MorphoDepositInput(BaseModel): - """Input schema for Morpho Vault deposit action.""" - - vault_address: str - assets: str - receiver: str - token_address: str - - -DEPOSIT_PROMPT = """ -This tool allows depositing assets into a Morpho Vault. It takes: - -- vault_address: The address of the Morpho Vault to deposit to -- assets: The amount of assets to deposit in whole units - Examples for WETH: - - 1 WETH - - 0.1 WETH - - 0.01 WETH -- receiver: The address to receive the shares -- token_address: The address of the token to approve -""" - - -def deposit_to_morpho( - wallet: Wallet, - vault_address: str, - assets: str, - receiver: str, - token_address: str, -) -> str: - """Deposit assets into a Morpho Vault. - - Args: - wallet (Wallet): The wallet to execute the deposit from - vault_address (str): The address of the Morpho Vault - assets (str): The amount of assets to deposit in whole units (e.g., 0.01 WETH) - receiver (str): The address to receive the shares - token_address (str): The address of the token to approve - - Returns: - str: A success message with transaction hash or error message - - """ - if float(assets) <= 0: - return "Error: Assets amount must be greater than 0" - - try: - token_asset = Asset.fetch(wallet.network_id, token_address) - - atomic_assets = str(int(token_asset.to_atomic_amount(Decimal(assets)))) - - approval_result = approve(wallet, token_address, vault_address, atomic_assets) - if approval_result.startswith("Error"): - return f"Error approving Morpho Vault as spender: {approval_result}" - - deposit_args = {"assets": atomic_assets, "receiver": receiver} - - invocation = wallet.invoke_contract( - contract_address=vault_address, - method="deposit", - abi=METAMORPHO_ABI, - args=deposit_args, - ).wait() - - return f"Deposited {assets} to Morpho Vault {vault_address} with transaction hash: {invocation.transaction_hash} and transaction link: {invocation.transaction_link}" - - except Exception as e: - return f"Error depositing to Morpho Vault: {e!s}" - - -class MorphoDepositAction(CdpAction): - """Morpho Vault deposit action.""" - - name: str = "morpho_deposit" - description: str = DEPOSIT_PROMPT - args_schema: type[BaseModel] = MorphoDepositInput - func: Callable[..., str] = deposit_to_morpho diff --git a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/utils.py b/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/utils.py deleted file mode 100644 index 4c01492c8..000000000 --- a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/utils.py +++ /dev/null @@ -1,35 +0,0 @@ -from cdp import Wallet - -from cdp_agentkit_core.actions.morpho.constants import ERC20_APPROVE_ABI - - -def approve(wallet: Wallet, token_address: str, spender: str, amount: int) -> str: - """Approve a spender to spend a specified amount of tokens. - - Args: - wallet (Wallet): The wallet to execute the approval from - token_address (str): The address of the token contract - spender (str): The address of the spender - amount (int): The amount of tokens to approve - - Returns: - str: A success message with transaction hash or error message - - """ - try: - amount_str = str(amount) - - invocation = wallet.invoke_contract( - contract_address=token_address, - method="approve", - abi=ERC20_APPROVE_ABI, - args={ - "spender": spender, - "value": amount_str, - }, - ).wait() - - return f"Approved {amount} tokens for {spender} with transaction hash: {invocation.transaction_hash} and transaction link: {invocation.transaction_link}" - - except Exception as e: - return f"Error approving tokens: {e!s}" diff --git a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/withdraw.py b/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/withdraw.py deleted file mode 100644 index 08be2cd13..000000000 --- a/cdp-agentkit-core/python/cdp_agentkit_core/actions/morpho/withdraw.py +++ /dev/null @@ -1,67 +0,0 @@ -from collections.abc import Callable - -from cdp import Wallet -from pydantic import BaseModel - -from cdp_agentkit_core.actions import CdpAction -from cdp_agentkit_core.actions.morpho.constants import METAMORPHO_ABI - - -class MorphoWithdrawInput(BaseModel): - """Input schema for Morpho Vault withdraw action.""" - - vault_address: str - assets: str - receiver: str - - -WITHDRAW_PROMPT = """ -This tool allows withdrawing assets from a Morpho Vault. It takes: - -- vault_address: The address of the Morpho Vault to withdraw from -- assets: The amount of assets to withdraw in atomic units -- receiver: The address to receive the shares -""" - - -def withdraw_from_morpho(wallet: Wallet, vault_address: str, assets: str, receiver: str) -> str: - """Withdraw assets from a Morpho Vault. - - Args: - wallet (Wallet): The wallet to execute the deposit from - vault_address (str): The address of the Morpho Vault - assets (str): The amount of assets to withdraw in atomic units - receiver (str): The address to receive the shares - - Returns: - str: A success message with transaction hash or error message - - """ - if int(assets) <= 0: - return "Error: Assets amount must be greater than 0" - - try: - invocation = wallet.invoke_contract( - contract_address=vault_address, - method="withdraw", - abi=METAMORPHO_ABI, - args={ - "assets": assets, - "receiver": receiver, - "owner": receiver, - }, - ).wait() - - return f"Withdrawn {assets} from Morpho Vault {vault_address} with transaction hash: {invocation.transaction_hash} and transaction link: {invocation.transaction_link}" - - except Exception as e: - return f"Error withdrawing from Morpho Vault: {e!s}" - - -class MorphoWithdrawAction(CdpAction): - """Morpho Vault withdraw action.""" - - name: str = "morpho_withdraw" - description: str = WITHDRAW_PROMPT - args_schema: type[BaseModel] = MorphoWithdrawInput - func: Callable[..., str] = withdraw_from_morpho diff --git a/cdp-agentkit-core/python/tests/actions/morpho/test_deposit.py b/cdp-agentkit-core/python/tests/actions/morpho/test_deposit.py deleted file mode 100644 index 57f8270f7..000000000 --- a/cdp-agentkit-core/python/tests/actions/morpho/test_deposit.py +++ /dev/null @@ -1,167 +0,0 @@ -from decimal import Decimal -from unittest.mock import patch - -import pytest - -from cdp_agentkit_core.actions.morpho.constants import METAMORPHO_ABI -from cdp_agentkit_core.actions.morpho.deposit import ( - MorphoDepositInput, - deposit_to_morpho, -) - -MOCK_VAULT_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" -MOCK_ASSETS_WETH = "1000000000000000000" -MOCK_NETWORK_ID = "base-sepolia" -MOCK_WALLET_ADDRESS = "0x1234567890123456789012345678901234567890" -MOCK_TOKEN_ADDRESS = "0x4200000000000000000000000000000000000006" -MOCK_DECIMALS = 18 -MOCK_ASSETS = "1" -MOCK_ASSETS_WEI = "1000000000000000000" - - -def test_deposit_input_model_valid(): - """Test that MorphoDepositInput accepts valid parameters.""" - input_model = MorphoDepositInput( - vault_address=MOCK_VAULT_ADDRESS, - assets=MOCK_ASSETS_WETH, - receiver=MOCK_WALLET_ADDRESS, - token_address=MOCK_TOKEN_ADDRESS, - ) - - assert input_model.vault_address == MOCK_VAULT_ADDRESS - assert input_model.assets == MOCK_ASSETS_WETH - assert input_model.receiver == MOCK_WALLET_ADDRESS - assert input_model.token_address == MOCK_TOKEN_ADDRESS - - -def test_deposit_input_model_missing_params(): - """Test that MorphoDepositInput raises error when params are missing.""" - with pytest.raises(ValueError): - MorphoDepositInput() - - -def test_deposit_success(wallet_factory, contract_invocation_factory, asset_factory): - """Test successful deposit with valid parameters.""" - mock_wallet = wallet_factory() - mock_contract_instance = contract_invocation_factory() - mock_wallet.default_address.address_id = MOCK_WALLET_ADDRESS - mock_wallet.network_id = MOCK_NETWORK_ID - mock_asset = asset_factory(decimals=MOCK_DECIMALS) - - with ( - patch( - "cdp_agentkit_core.actions.morpho.deposit.approve", return_value="Approval successful" - ) as mock_approve, - patch( - "cdp_agentkit_core.actions.morpho.deposit.Asset.fetch", return_value=mock_asset - ) as mock_get_asset, - patch.object( - mock_asset, "to_atomic_amount", return_value=MOCK_ASSETS_WEI - ) as mock_to_atomic_amount, - patch.object( - mock_wallet, "invoke_contract", return_value=mock_contract_instance - ) as mock_invoke, - patch.object( - mock_contract_instance, "wait", return_value=mock_contract_instance - ) as mock_contract_wait, - ): - action_response = deposit_to_morpho( - mock_wallet, - MOCK_VAULT_ADDRESS, - MOCK_ASSETS, - MOCK_WALLET_ADDRESS, - MOCK_TOKEN_ADDRESS, - ) - - expected_response = f"Deposited {MOCK_ASSETS} to Morpho Vault {MOCK_VAULT_ADDRESS} with transaction hash: {mock_contract_instance.transaction_hash} and transaction link: {mock_contract_instance.transaction_link}" - assert action_response == expected_response - - mock_approve.assert_called_once_with( - mock_wallet, MOCK_TOKEN_ADDRESS, MOCK_VAULT_ADDRESS, MOCK_ASSETS_WEI - ) - - mock_get_asset.assert_called_once_with(MOCK_NETWORK_ID, MOCK_TOKEN_ADDRESS) - - mock_to_atomic_amount.assert_called_once_with(Decimal(MOCK_ASSETS)) - - mock_invoke.assert_called_once_with( - contract_address=MOCK_VAULT_ADDRESS, - method="deposit", - abi=METAMORPHO_ABI, - args={"assets": MOCK_ASSETS_WEI, "receiver": MOCK_WALLET_ADDRESS}, - ) - mock_contract_wait.assert_called_once_with() - - -def test_deposit_api_error(wallet_factory, asset_factory): - """Test deposit when API error occurs.""" - mock_wallet = wallet_factory() - mock_wallet.default_address.address_id = MOCK_WALLET_ADDRESS - mock_wallet.network_id = MOCK_NETWORK_ID - mock_asset = asset_factory(decimals=MOCK_DECIMALS) - - with ( - patch( - "cdp_agentkit_core.actions.morpho.deposit.approve", return_value="Approval successful" - ), - patch( - "cdp_agentkit_core.actions.morpho.deposit.Asset.fetch", return_value=mock_asset - ) as mock_get_asset, - patch.object( - mock_asset, "to_atomic_amount", return_value=MOCK_ASSETS_WEI - ) as mock_to_atomic_amount, - patch.object(mock_wallet, "invoke_contract", side_effect=Exception("API error")), - ): - action_response = deposit_to_morpho( - mock_wallet, - MOCK_VAULT_ADDRESS, - MOCK_ASSETS, # Using non-wei value - MOCK_WALLET_ADDRESS, - MOCK_TOKEN_ADDRESS, - ) - - expected_response = "Error depositing to Morpho Vault: API error" - assert action_response == expected_response - - mock_get_asset.assert_called_once_with(MOCK_NETWORK_ID, MOCK_TOKEN_ADDRESS) - - mock_to_atomic_amount.assert_called_once_with(Decimal(MOCK_ASSETS)) - - -def test_deposit_approval_failure(wallet_factory, asset_factory): - """Test deposit when approval fails.""" - mock_wallet = wallet_factory() - mock_wallet.default_address.address_id = MOCK_WALLET_ADDRESS - mock_wallet.network_id = MOCK_NETWORK_ID - mock_asset = asset_factory(decimals=MOCK_DECIMALS) - - with ( - patch( - "cdp_agentkit_core.actions.morpho.deposit.approve", - return_value="Error: Approval failed", - ) as mock_approve, - patch( - "cdp_agentkit_core.actions.morpho.deposit.Asset.fetch", return_value=mock_asset - ) as mock_get_asset, - patch.object( - mock_asset, "to_atomic_amount", return_value=MOCK_ASSETS_WEI - ) as mock_to_atomic_amount, - ): - action_response = deposit_to_morpho( - mock_wallet, - MOCK_VAULT_ADDRESS, - MOCK_ASSETS, # Using non-wei value - MOCK_WALLET_ADDRESS, - MOCK_TOKEN_ADDRESS, - ) - - expected_response = "Error approving Morpho Vault as spender: Error: Approval failed" - assert action_response == expected_response - - mock_approve.assert_called_once_with( - mock_wallet, MOCK_TOKEN_ADDRESS, MOCK_VAULT_ADDRESS, MOCK_ASSETS_WEI - ) - - mock_get_asset.assert_called_once_with(MOCK_NETWORK_ID, MOCK_TOKEN_ADDRESS) - - mock_to_atomic_amount.assert_called_once_with(Decimal(MOCK_ASSETS)) diff --git a/cdp-agentkit-core/python/tests/actions/morpho/test_withdraw.py b/cdp-agentkit-core/python/tests/actions/morpho/test_withdraw.py deleted file mode 100644 index aa090e438..000000000 --- a/cdp-agentkit-core/python/tests/actions/morpho/test_withdraw.py +++ /dev/null @@ -1,92 +0,0 @@ -from unittest.mock import patch - -import pytest - -from cdp_agentkit_core.actions.morpho.constants import METAMORPHO_ABI -from cdp_agentkit_core.actions.morpho.withdraw import ( - MorphoWithdrawInput, - withdraw_from_morpho, -) - -MOCK_VAULT_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" -MOCK_ASSETS_WETH = "1000000000000000000" -MOCK_NETWORK_ID = "base-sepolia" -MOCK_WALLET_ADDRESS = "0x1234567890123456789012345678901234567890" - - -def test_deposit_input_model_valid(): - """Test that MorphoWithdrawInput accepts valid parameters.""" - input_model = MorphoWithdrawInput( - vault_address=MOCK_VAULT_ADDRESS, - assets=MOCK_ASSETS_WETH, - receiver=MOCK_WALLET_ADDRESS, - ) - - assert input_model.vault_address == MOCK_VAULT_ADDRESS - assert input_model.assets == MOCK_ASSETS_WETH - assert input_model.receiver == MOCK_WALLET_ADDRESS - - -def test_withdraw_input_model_missing_params(): - """Test that MorphoWithdrawInput raises error when params are missing.""" - with pytest.raises(ValueError): - MorphoWithdrawInput() - - -def test_withdraw_success(wallet_factory, contract_invocation_factory): - """Test successful withdraw with valid parameters.""" - mock_wallet = wallet_factory() - mock_contract_instance = contract_invocation_factory() - mock_wallet.default_address.address_id = MOCK_WALLET_ADDRESS - mock_wallet.network_id = MOCK_NETWORK_ID - - with ( - patch.object( - mock_wallet, "invoke_contract", return_value=mock_contract_instance - ) as mock_invoke, - patch.object( - mock_contract_instance, "wait", return_value=mock_contract_instance - ) as mock_contract_wait, - ): - action_response = withdraw_from_morpho( - mock_wallet, - MOCK_VAULT_ADDRESS, - MOCK_ASSETS_WETH, - MOCK_WALLET_ADDRESS, - ) - - expected_response = f"Withdrawn {MOCK_ASSETS_WETH} from Morpho Vault {MOCK_VAULT_ADDRESS} with transaction hash: {mock_contract_instance.transaction_hash} and transaction link: {mock_contract_instance.transaction_link}" - assert action_response == expected_response - - mock_invoke.assert_called_once_with( - contract_address=MOCK_VAULT_ADDRESS, - method="withdraw", - abi=METAMORPHO_ABI, - args={ - "assets": MOCK_ASSETS_WETH, - "receiver": MOCK_WALLET_ADDRESS, - "owner": MOCK_WALLET_ADDRESS, - }, - ) - mock_contract_wait.assert_called_once_with() - - -def test_withdraw_api_error(wallet_factory): - """Test withdraw when API error occurs.""" - mock_wallet = wallet_factory() - mock_wallet.default_address.address_id = MOCK_WALLET_ADDRESS - mock_wallet.network_id = MOCK_NETWORK_ID - - with patch.object( - mock_wallet, "invoke_contract", side_effect=Exception("API error") - ) as mock_invoke: - action_response = withdraw_from_morpho( - mock_wallet, - MOCK_VAULT_ADDRESS, - MOCK_ASSETS_WETH, - MOCK_WALLET_ADDRESS, - ) - - expected_response = "Error withdrawing from Morpho Vault: API error" - assert action_response == expected_response - mock_invoke.assert_called_once() diff --git a/cdp-agentkit-core/python/tests/factories/asset_factory.py b/cdp-agentkit-core/python/tests/factories/asset_factory.py deleted file mode 100644 index 39a7ebd7b..000000000 --- a/cdp-agentkit-core/python/tests/factories/asset_factory.py +++ /dev/null @@ -1,17 +0,0 @@ -from unittest.mock import Mock - -import pytest -from cdp.asset import Asset - - -@pytest.fixture -def asset_factory(): - """Create and return a factory for creating Asset fixtures.""" - - def _create_asset(network_id="base-sepolia", asset_id="usdc", decimals=6): - asset_mock = Mock(spec=Asset) - asset_mock.decimals = decimals - - return asset_mock - - return _create_asset