From 9126e735753f9777a650766e11a1ebfd87987a80 Mon Sep 17 00:00:00 2001 From: Chris Gerber Date: Thu, 7 Nov 2024 10:33:59 -0800 Subject: [PATCH 1/2] feat: action for twitter account details (#23) * first pass implementing twitter account details action * removing unused twitter api wrapper var * cleanup * implementing John's feedback --------- Co-authored-by: John Peterson <98187317+John-peterson-coinbase@users.noreply.github.com> --- .../actions/social/twitter/__init__.py | 15 +++-- .../actions/social/twitter/account_details.py | 36 +++++++++++ .../examples/account_details/Makefile | 10 ++++ .../account_details/account_details.py | 59 +++++++++++++++++++ .../examples/post_tweet/post_tweet.py | 7 +-- .../twitter_langchain/twitter_api_wrapper.py | 22 ++++--- .../twitter_langchain/twitter_toolkit.py | 15 ++++- 7 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py create mode 100644 twitter-langchain/examples/account_details/Makefile create mode 100644 twitter-langchain/examples/account_details/account_details.py diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py index 4555629c5..8af0f009c 100644 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py @@ -1,9 +1,14 @@ -from cdp_agentkit_core.actions.social.twitter.post_tweet import ( - POST_TWEET_PROMPT as POST_TWEET_PROMPT, +from cdp_agentkit_core.actions.social.twitter.account_details import ( + ACCOUNT_DETAILS_PROMPT as ACCOUNT_DETAILS_PROMPT, ) -from cdp_agentkit_core.actions.social.twitter.post_tweet import ( - PostTweetInput as PostTweetInput, +from cdp_agentkit_core.actions.social.twitter.account_details import ( + AccountDetailsInput as AccountDetailsInput, +) +from cdp_agentkit_core.actions.social.twitter.account_details import ( + account_details as account_details, ) from cdp_agentkit_core.actions.social.twitter.post_tweet import ( - post_tweet as post_tweet, + POST_TWEET_PROMPT as POST_TWEET_PROMPT, ) +from cdp_agentkit_core.actions.social.twitter.post_tweet import PostTweetInput as PostTweetInput +from cdp_agentkit_core.actions.social.twitter.post_tweet import post_tweet as post_tweet diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py new file mode 100644 index 000000000..dc2902830 --- /dev/null +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py @@ -0,0 +1,36 @@ +import tweepy +from pydantic import BaseModel, Field + +ACCOUNT_DETAILS_PROMPT = """ +This tool will return account details for the currently authenticated Twitter (X) user context.""" + +class AccountDetailsInput(BaseModel): + """Input argument schema for Twitter account details action.""" + + no_input: str = Field( + "", + description="No input required, e.g. `` (empty string).", + ) + +def account_details(client: tweepy.Client) -> str: + """Get the authenticated Twitter (X) user account details. + + Returns: + str: A message containing account details for the authenticated user context. + + """ + message = "" + + try: + response = client.get_me() + user = response.data + + message = f"""Successfully retrieved authenticated user account details. Please present the following as json and not markdown: + id: {user.id} + name: {user.name} + username: {user.username} + link: https://x.com/{user.username}""" + except tweepy.errors.TweepyException as e: + message = f"Error retrieving authenticated user account details: {e}" + + return message diff --git a/twitter-langchain/examples/account_details/Makefile b/twitter-langchain/examples/account_details/Makefile new file mode 100644 index 000000000..b2bf7df51 --- /dev/null +++ b/twitter-langchain/examples/account_details/Makefile @@ -0,0 +1,10 @@ +ifneq (,$(wildcard ./.env)) + include .env +endif + +export + +.PHONY: run +run: + poetry install --with dev + poetry run python account_details.py diff --git a/twitter-langchain/examples/account_details/account_details.py b/twitter-langchain/examples/account_details/account_details.py new file mode 100644 index 000000000..f5559a9ee --- /dev/null +++ b/twitter-langchain/examples/account_details/account_details.py @@ -0,0 +1,59 @@ + +from langchain_core.messages import HumanMessage +from langchain_openai import ChatOpenAI +from langgraph.prebuilt import create_react_agent + +from twitter_langchain import TwitterApiWrapper, TwitterToolkit + +# Initialize TwitterApiwrapper +twitter_api_wrapper = TwitterApiWrapper() + +# Create TwitterToolkit from the api wrapper +twitter_toolkit = TwitterToolkit.from_twitter_api_wrapper(twitter_api_wrapper) + +# View available tools +tools = twitter_toolkit.get_tools() +for tool in tools: + print(tool.name) + +# Initialize LLM +llm = ChatOpenAI(model="gpt-4o-mini") + +# Create agent +agent_executor = create_react_agent(llm, tools) + +# Example - get account details +events = agent_executor.stream( + { + "messages": [ + HumanMessage(content="Please obtain my twitter account information"), + ], + }, + stream_mode="values", +) + +for event in events: + event["messages"][-1].pretty_print() + +# ================================ Human Message ================================= +# Please obtain my twitter account information +# ================================== Ai Message ================================== +# Tool Calls: +# account_details (call_pYME8H1tHfdMakFZ1FTS0VBX) +# Call ID: call_pYME8H1tHfdMakFZ1FTS0VBX +# Args: +# ================================= Tool Message ================================= +# Name: account_details + +# Successfully retrieved authenticated user account details. Please present the following as json and not markdown: +# id: 1234567890123456789 +# name: My Twitter Name +# username: MyTwitterUserName +# link: https://x.com/MyTwitterUserName +# ================================== Ai Message ================================== +# { +# "id": "1234567890123456789", +# "name": "My Twitter Name", +# "username": "MyTwitterUserName", +# "link": "https://x.com/MyTwitterUserName" +# } diff --git a/twitter-langchain/examples/post_tweet/post_tweet.py b/twitter-langchain/examples/post_tweet/post_tweet.py index 69fb690dc..d5faba9cd 100644 --- a/twitter-langchain/examples/post_tweet/post_tweet.py +++ b/twitter-langchain/examples/post_tweet/post_tweet.py @@ -1,13 +1,10 @@ import uuid -from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage +from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent -from twitter_langchain import ( - TwitterApiWrapper, - TwitterToolkit -) +from twitter_langchain import TwitterApiWrapper, TwitterToolkit # Initialize TwitterApiwrapper twitter_api_wrapper = TwitterApiWrapper() diff --git a/twitter-langchain/twitter_langchain/twitter_api_wrapper.py b/twitter-langchain/twitter_langchain/twitter_api_wrapper.py index 7acdde7e5..5b63dc031 100644 --- a/twitter-langchain/twitter_langchain/twitter_api_wrapper.py +++ b/twitter-langchain/twitter_langchain/twitter_api_wrapper.py @@ -1,20 +1,18 @@ """Util that calls Twitter API.""" - from typing import Any -from langchain_core.utils import get_from_dict_or_env -from pydantic import BaseModel, model_validator - from cdp_agentkit_core.actions.social.twitter import ( + account_details, post_tweet, ) +from langchain_core.utils import get_from_dict_or_env +from pydantic import BaseModel, model_validator class TwitterApiWrapper(BaseModel): """Wrapper for Twitter API.""" - bearer_token: str | None = None client: Any | None = None @model_validator(mode="before") @@ -48,6 +46,15 @@ def validate_environment(cls, values: dict) -> Any: return values + def account_details_wrapper(self) -> str: + """Get the authenticated Twitter (X) user account details. + + Returns: + str: A message containing account details for the authenticated user context in JSON format. + + """ + return account_details(client=self.client) + def post_tweet_wrapper(self, tweet: str) -> str: """Post tweet to Twitter. @@ -59,12 +66,13 @@ def post_tweet_wrapper(self, tweet: str) -> str: str: A message containing the result of the post action and the tweet. """ - return post_tweet(client=self.client, tweet=tweet) def run(self, mode: str, **kwargs) -> str: """Run the action via the Twitter API.""" - if mode == "post_tweet": + if mode == "account_details": + return self.account_details_wrapper() + elif mode == "post_tweet": return self.post_tweet_wrapper(**kwargs) else: raise ValueError("Invalid mode: " + mode) diff --git a/twitter-langchain/twitter_langchain/twitter_toolkit.py b/twitter-langchain/twitter_langchain/twitter_toolkit.py index a712e1bed..af46e4e0c 100644 --- a/twitter-langchain/twitter_langchain/twitter_toolkit.py +++ b/twitter-langchain/twitter_langchain/twitter_toolkit.py @@ -1,12 +1,14 @@ """TwitterToolkit.""" -from langchain_core.tools import BaseTool -from langchain_core.tools.base import BaseToolkit - from cdp_agentkit_core.actions.social.twitter import ( + ACCOUNT_DETAILS_PROMPT, POST_TWEET_PROMPT, + AccountDetailsInput, PostTweetInput, ) +from langchain_core.tools import BaseTool +from langchain_core.tools.base import BaseToolkit + from twitter_langchain.twitter_action import TwitterAction from twitter_langchain.twitter_api_wrapper import TwitterApiWrapper @@ -55,6 +57,7 @@ class TwitterToolkit(BaseToolkit): .. code-block:: none + account_details post_tweet Use within an agent: @@ -120,6 +123,12 @@ def from_twitter_api_wrapper(cls, twitter_api_wrapper: TwitterApiWrapper) -> "Tw """ actions: list[dict] = [ + { + "mode": "account_details", + "name": "account_details", + "description": ACCOUNT_DETAILS_PROMPT, + "args_schema": AccountDetailsInput, + }, { "mode": "post_tweet", "name": "post_tweet", From bfabef0efec1a14b163586d6a4acc8dd3e6a089e Mon Sep 17 00:00:00 2001 From: Alexander Stone Date: Thu, 7 Nov 2024 12:06:11 -0800 Subject: [PATCH 2/2] chore: Remove Uniswap functionality (#27) This removes Uniswap pool management functionality from the main branch. This will be reintroduced once we have full support of managing liquidity within the pools from our SDK. --- README.md | 2 +- cdp-agentkit-core/CHANGELOG.md | 3 - .../cdp_agentkit_core/actions/__init__.py | 10 - .../actions/uniswap_v3/constants.py | 548 ------------------ .../actions/uniswap_v3/create_pool.py | 67 --- .../actions/uniswap_v3/get_pool.py | 70 --- .../actions/uniswap_v3/get_pool_liquidity.py | 57 -- .../actions/uniswap_v3/get_pool_observe.py | 67 --- .../actions/uniswap_v3/get_pool_slot0.py | 62 -- .../actions/uniswap_v3/test_create_pool.py | 85 --- .../uniswap_v3/test_get_pool_liquidity.py | 68 --- .../uniswap_v3/test_get_pool_observe.py | 74 --- .../actions/uniswap_v3/test_get_pool_slot0.py | 76 --- cdp-langchain/CHANGELOG.md | 3 - .../agent_toolkits/cdp_toolkit.py | 5 - 15 files changed, 1 insertion(+), 1196 deletions(-) delete mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/constants.py delete mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/create_pool.py delete mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool.py delete mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_liquidity.py delete mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_observe.py delete mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_slot0.py delete mode 100644 cdp-agentkit-core/tests/actions/uniswap_v3/test_create_pool.py delete mode 100644 cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_liquidity.py delete mode 100644 cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_observe.py delete mode 100644 cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_slot0.py diff --git a/README.md b/README.md index efe122639..4715430b1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Coinbase Developer Platform (CDP) Agentkit simplifies bringing your AI Agent - Getting wallet details and balances - Transferring and trading tokens - Registering Basenames - - Deploying ERC20 tokens and creating uniswap_v3 pools for trading + - Deploying ERC20 tokens - Deploying ERC721 tokens and minting NFTs ## Examples diff --git a/cdp-agentkit-core/CHANGELOG.md b/cdp-agentkit-core/CHANGELOG.md index be6012074..7466d3587 100644 --- a/cdp-agentkit-core/CHANGELOG.md +++ b/cdp-agentkit-core/CHANGELOG.md @@ -4,9 +4,6 @@ ### Added -- Added `uniswap_v3_create_pool` action. -- Added `uniswap_v3_get_pool`, `uniswap_v3_get_pool_observe`, `uniswap_v3_get_pool_slot0`, and `uniswap_v3_get_pool_liquidity` actions. - ## [0.0.1] - 2024-11-04 ### Added diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py b/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py index df6d4f45c..f49029b8d 100644 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py @@ -8,11 +8,6 @@ from cdp_agentkit_core.actions.request_faucet_funds import RequestFaucetFundsAction from cdp_agentkit_core.actions.trade import TradeAction from cdp_agentkit_core.actions.transfer import TransferAction -from cdp_agentkit_core.actions.uniswap_v3.create_pool import UniswapV3CreatePoolAction -from cdp_agentkit_core.actions.uniswap_v3.get_pool import UniswapV3GetPoolAction -from cdp_agentkit_core.actions.uniswap_v3.get_pool_liquidity import UniswapV3GetPoolLiquidityAction -from cdp_agentkit_core.actions.uniswap_v3.get_pool_observe import UniswapV3GetPoolObserveAction -from cdp_agentkit_core.actions.uniswap_v3.get_pool_slot0 import UniswapV3GetPoolSlot0Action # WARNING: All new CdpAction subclasses must be imported above, otherwise they will not be discovered @@ -38,10 +33,5 @@ def get_all_cdp_actions() -> list[type[CdpAction]]: "RequestFaucetFundsAction", "TradeAction", "TransferAction", - "UniswapV3CreatePoolAction", - "UniswapV3GetPoolAction", - "UniswapV3GetPoolSlot0Action", - "UniswapV3GetPoolObserveAction", - "UniswapV3GetPoolLiquidityAction", "CDP_ACTIONS", ] diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/constants.py b/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/constants.py deleted file mode 100644 index 14ceb3d02..000000000 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/constants.py +++ /dev/null @@ -1,548 +0,0 @@ -UNISWAP_V3_FACTORY_ABI = [ - {"inputs": [], "stateMutability": "nonpayable", "type": "constructor"}, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "uint24", "name": "fee", "type": "uint24"}, - {"indexed": True, "internalType": "int24", "name": "tickSpacing", "type": "int24"}, - ], - "name": "FeeAmountEnabled", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "oldOwner", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "newOwner", "type": "address"}, - ], - "name": "OwnerChanged", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "token0", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "token1", "type": "address"}, - {"indexed": True, "internalType": "uint24", "name": "fee", "type": "uint24"}, - {"indexed": False, "internalType": "int24", "name": "tickSpacing", "type": "int24"}, - {"indexed": False, "internalType": "address", "name": "pool", "type": "address"}, - ], - "name": "PoolCreated", - "type": "event", - }, - { - "inputs": [ - {"internalType": "address", "name": "tokenA", "type": "address"}, - {"internalType": "address", "name": "tokenB", "type": "address"}, - {"internalType": "uint24", "name": "fee", "type": "uint24"}, - ], - "name": "createPool", - "outputs": [{"internalType": "address", "name": "pool", "type": "address"}], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint24", "name": "fee", "type": "uint24"}, - {"internalType": "int24", "name": "tickSpacing", "type": "int24"}, - ], - "name": "enableFeeAmount", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint24", "name": "", "type": "uint24"}], - "name": "feeAmountTickSpacing", - "outputs": [{"internalType": "int24", "name": "", "type": "int24"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "tokenA", "type": "address"}, - {"internalType": "address", "name": "tokenB", "type": "address"}, - {"internalType": "uint24", "name": "fee", "type": "uint24"}, - ], - "name": "getPool", - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "owner", - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "parameters", - "outputs": [ - {"internalType": "address", "name": "factory", "type": "address"}, - {"internalType": "address", "name": "token0", "type": "address"}, - {"internalType": "address", "name": "token1", "type": "address"}, - {"internalType": "uint24", "name": "fee", "type": "uint24"}, - {"internalType": "int24", "name": "tickSpacing", "type": "int24"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "address", "name": "_owner", "type": "address"}], - "name": "setOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, -] - -UNISWAP_V3_POOL_ABI = [ - {"inputs": [], "stateMutability": "nonpayable", "type": "constructor"}, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "owner", "type": "address"}, - {"indexed": True, "internalType": "int24", "name": "tickLower", "type": "int24"}, - {"indexed": True, "internalType": "int24", "name": "tickUpper", "type": "int24"}, - {"indexed": False, "internalType": "uint128", "name": "amount", "type": "uint128"}, - {"indexed": False, "internalType": "uint256", "name": "amount0", "type": "uint256"}, - {"indexed": False, "internalType": "uint256", "name": "amount1", "type": "uint256"}, - ], - "name": "Burn", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "owner", "type": "address"}, - {"indexed": False, "internalType": "address", "name": "recipient", "type": "address"}, - {"indexed": True, "internalType": "int24", "name": "tickLower", "type": "int24"}, - {"indexed": True, "internalType": "int24", "name": "tickUpper", "type": "int24"}, - {"indexed": False, "internalType": "uint128", "name": "amount0", "type": "uint128"}, - {"indexed": False, "internalType": "uint128", "name": "amount1", "type": "uint128"}, - ], - "name": "Collect", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "recipient", "type": "address"}, - {"indexed": False, "internalType": "uint128", "name": "amount0", "type": "uint128"}, - {"indexed": False, "internalType": "uint128", "name": "amount1", "type": "uint128"}, - ], - "name": "CollectProtocol", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "recipient", "type": "address"}, - {"indexed": False, "internalType": "uint256", "name": "amount0", "type": "uint256"}, - {"indexed": False, "internalType": "uint256", "name": "amount1", "type": "uint256"}, - {"indexed": False, "internalType": "uint256", "name": "paid0", "type": "uint256"}, - {"indexed": False, "internalType": "uint256", "name": "paid1", "type": "uint256"}, - ], - "name": "Flash", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint16", - "name": "observationCardinalityNextOld", - "type": "uint16", - }, - { - "indexed": False, - "internalType": "uint16", - "name": "observationCardinalityNextNew", - "type": "uint16", - }, - ], - "name": "IncreaseObservationCardinalityNext", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint160", - "name": "sqrtPriceX96", - "type": "uint160", - }, - {"indexed": False, "internalType": "int24", "name": "tick", "type": "int24"}, - ], - "name": "Initialize", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": False, "internalType": "address", "name": "sender", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "owner", "type": "address"}, - {"indexed": True, "internalType": "int24", "name": "tickLower", "type": "int24"}, - {"indexed": True, "internalType": "int24", "name": "tickUpper", "type": "int24"}, - {"indexed": False, "internalType": "uint128", "name": "amount", "type": "uint128"}, - {"indexed": False, "internalType": "uint256", "name": "amount0", "type": "uint256"}, - {"indexed": False, "internalType": "uint256", "name": "amount1", "type": "uint256"}, - ], - "name": "Mint", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": False, "internalType": "uint8", "name": "feeProtocol0Old", "type": "uint8"}, - {"indexed": False, "internalType": "uint8", "name": "feeProtocol1Old", "type": "uint8"}, - {"indexed": False, "internalType": "uint8", "name": "feeProtocol0New", "type": "uint8"}, - {"indexed": False, "internalType": "uint8", "name": "feeProtocol1New", "type": "uint8"}, - ], - "name": "SetFeeProtocol", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "recipient", "type": "address"}, - {"indexed": False, "internalType": "int256", "name": "amount0", "type": "int256"}, - {"indexed": False, "internalType": "int256", "name": "amount1", "type": "int256"}, - { - "indexed": False, - "internalType": "uint160", - "name": "sqrtPriceX96", - "type": "uint160", - }, - {"indexed": False, "internalType": "uint128", "name": "liquidity", "type": "uint128"}, - {"indexed": False, "internalType": "int24", "name": "tick", "type": "int24"}, - ], - "name": "Swap", - "type": "event", - }, - { - "inputs": [ - {"internalType": "int24", "name": "tickLower", "type": "int24"}, - {"internalType": "int24", "name": "tickUpper", "type": "int24"}, - {"internalType": "uint128", "name": "amount", "type": "uint128"}, - ], - "name": "burn", - "outputs": [ - {"internalType": "uint256", "name": "amount0", "type": "uint256"}, - {"internalType": "uint256", "name": "amount1", "type": "uint256"}, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "recipient", "type": "address"}, - {"internalType": "int24", "name": "tickLower", "type": "int24"}, - {"internalType": "int24", "name": "tickUpper", "type": "int24"}, - {"internalType": "uint128", "name": "amount0Requested", "type": "uint128"}, - {"internalType": "uint128", "name": "amount1Requested", "type": "uint128"}, - ], - "name": "collect", - "outputs": [ - {"internalType": "uint128", "name": "amount0", "type": "uint128"}, - {"internalType": "uint128", "name": "amount1", "type": "uint128"}, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "recipient", "type": "address"}, - {"internalType": "uint128", "name": "amount0Requested", "type": "uint128"}, - {"internalType": "uint128", "name": "amount1Requested", "type": "uint128"}, - ], - "name": "collectProtocol", - "outputs": [ - {"internalType": "uint128", "name": "amount0", "type": "uint128"}, - {"internalType": "uint128", "name": "amount1", "type": "uint128"}, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "factory", - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "fee", - "outputs": [{"internalType": "uint24", "name": "", "type": "uint24"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "feeGrowthGlobal0X128", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "feeGrowthGlobal1X128", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "recipient", "type": "address"}, - {"internalType": "uint256", "name": "amount0", "type": "uint256"}, - {"internalType": "uint256", "name": "amount1", "type": "uint256"}, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "name": "flash", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint16", "name": "observationCardinalityNext", "type": "uint16"} - ], - "name": "increaseObservationCardinalityNext", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint160", "name": "sqrtPriceX96", "type": "uint160"}], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "liquidity", - "outputs": [{"internalType": "uint128", "name": "", "type": "uint128"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "maxLiquidityPerTick", - "outputs": [{"internalType": "uint128", "name": "", "type": "uint128"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "recipient", "type": "address"}, - {"internalType": "int24", "name": "tickLower", "type": "int24"}, - {"internalType": "int24", "name": "tickUpper", "type": "int24"}, - {"internalType": "uint128", "name": "amount", "type": "uint128"}, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "name": "mint", - "outputs": [ - {"internalType": "uint256", "name": "amount0", "type": "uint256"}, - {"internalType": "uint256", "name": "amount1", "type": "uint256"}, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "name": "observations", - "outputs": [ - {"internalType": "uint32", "name": "blockTimestamp", "type": "uint32"}, - {"internalType": "int56", "name": "tickCumulative", "type": "int56"}, - { - "internalType": "uint160", - "name": "secondsPerLiquidityCumulativeX128", - "type": "uint160", - }, - {"internalType": "bool", "name": "initialized", "type": "bool"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "uint32[]", "name": "secondsAgos", "type": "uint32[]"}], - "name": "observe", - "outputs": [ - {"internalType": "int56[]", "name": "tickCumulatives", "type": "int56[]"}, - { - "internalType": "uint160[]", - "name": "secondsPerLiquidityCumulativeX128s", - "type": "uint160[]", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "name": "positions", - "outputs": [ - {"internalType": "uint128", "name": "liquidity", "type": "uint128"}, - {"internalType": "uint256", "name": "feeGrowthInside0LastX128", "type": "uint256"}, - {"internalType": "uint256", "name": "feeGrowthInside1LastX128", "type": "uint256"}, - {"internalType": "uint128", "name": "tokensOwed0", "type": "uint128"}, - {"internalType": "uint128", "name": "tokensOwed1", "type": "uint128"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "protocolFees", - "outputs": [ - {"internalType": "uint128", "name": "token0", "type": "uint128"}, - {"internalType": "uint128", "name": "token1", "type": "uint128"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint8", "name": "feeProtocol0", "type": "uint8"}, - {"internalType": "uint8", "name": "feeProtocol1", "type": "uint8"}, - ], - "name": "setFeeProtocol", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "slot0", - "outputs": [ - {"internalType": "uint160", "name": "sqrtPriceX96", "type": "uint160"}, - {"internalType": "int24", "name": "tick", "type": "int24"}, - {"internalType": "uint16", "name": "observationIndex", "type": "uint16"}, - {"internalType": "uint16", "name": "observationCardinality", "type": "uint16"}, - {"internalType": "uint16", "name": "observationCardinalityNext", "type": "uint16"}, - {"internalType": "uint8", "name": "feeProtocol", "type": "uint8"}, - {"internalType": "bool", "name": "unlocked", "type": "bool"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "int24", "name": "tickLower", "type": "int24"}, - {"internalType": "int24", "name": "tickUpper", "type": "int24"}, - ], - "name": "snapshotCumulativesInside", - "outputs": [ - {"internalType": "int56", "name": "tickCumulativeInside", "type": "int56"}, - {"internalType": "uint160", "name": "secondsPerLiquidityInsideX128", "type": "uint160"}, - {"internalType": "uint32", "name": "secondsInside", "type": "uint32"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "recipient", "type": "address"}, - {"internalType": "bool", "name": "zeroForOne", "type": "bool"}, - {"internalType": "int256", "name": "amountSpecified", "type": "int256"}, - {"internalType": "uint160", "name": "sqrtPriceLimitX96", "type": "uint160"}, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "name": "swap", - "outputs": [ - {"internalType": "int256", "name": "amount0", "type": "int256"}, - {"internalType": "int256", "name": "amount1", "type": "int256"}, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "int16", "name": "", "type": "int16"}], - "name": "tickBitmap", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "tickSpacing", - "outputs": [{"internalType": "int24", "name": "", "type": "int24"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "int24", "name": "", "type": "int24"}], - "name": "ticks", - "outputs": [ - {"internalType": "uint128", "name": "liquidityGross", "type": "uint128"}, - {"internalType": "int128", "name": "liquidityNet", "type": "int128"}, - {"internalType": "uint256", "name": "feeGrowthOutside0X128", "type": "uint256"}, - {"internalType": "uint256", "name": "feeGrowthOutside1X128", "type": "uint256"}, - {"internalType": "int56", "name": "tickCumulativeOutside", "type": "int56"}, - { - "internalType": "uint160", - "name": "secondsPerLiquidityOutsideX128", - "type": "uint160", - }, - {"internalType": "uint32", "name": "secondsOutside", "type": "uint32"}, - {"internalType": "bool", "name": "initialized", "type": "bool"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "token0", - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "token1", - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, -] - - -UNISWAP_V3_FACTORY_CONTRACT_ADDRESSES = { - "base-sepolia": "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", - "base-mainnet": "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", - "ethereum-mainnet": "0x1F98431c8aD98523631AE4a59f267346ea31F984", - "arbitrum-mainnet": "0x1F98431c8aD98523631AE4a59f267346ea31F984", - "polygon-mainnet": "0x1F98431c8aD98523631AE4a59f267346ea31F984", -} - - -def get_contract_address(network: str) -> str: - """Get the Uniswap V3 Factory contract address for the specified network. - - Args: - network (str): The network ID to get the contract address for. - Valid networks are: base-sepolia, base-mainnet, ethereum-mainnet, - arbitrum-mainnet, polygon-mainnet. - - Returns: - str: The contract address for the specified network. - - Raises: - ValueError: If the specified network is not supported. - - """ - network = network.lower() - if network not in UNISWAP_V3_FACTORY_CONTRACT_ADDRESSES: - raise ValueError( - f"Invalid network: {network}. Valid networks are: {', '.join(UNISWAP_V3_FACTORY_CONTRACT_ADDRESSES.keys())}" - ) - return UNISWAP_V3_FACTORY_CONTRACT_ADDRESSES[network] diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/create_pool.py b/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/create_pool.py deleted file mode 100644 index beb6539e3..000000000 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/create_pool.py +++ /dev/null @@ -1,67 +0,0 @@ -from collections.abc import Callable - -from cdp import Wallet -from pydantic import BaseModel, Field - -from cdp_agentkit_core.actions import CdpAction -from cdp_agentkit_core.actions.uniswap_v3.constants import ( - UNISWAP_V3_FACTORY_ABI, - get_contract_address, -) - -UNISWAP_V3_CREATE_POOL_PROMPT = """ -This tool will create a Uniswap v3 pool for trading 2 tokens, one of which can be the native gas token. For native gas token, use the address 0x4200000000000000000000000000000000000006, and for ERC20 token, use its contract address. This tool takes the address of the first token, address of the second token, and the fee to charge for trades as inputs. The fee is denominated in hundredths of a bip (i.e. 1e-6) and must be passed a string. Acceptable fee values are 100, 500, 3000, and 10000. Supported networks are Base Sepolia, Base Mainnet, Ethereum Mainnet, Polygon Mainnet, and Arbitrum Mainnet.""" - - -class UniswapV3CreatePoolInput(BaseModel): - """Input argument schema for create pool action.""" - - token_a: str = Field( - ..., - description="The address of the first token to trade, e.g. 0x4200000000000000000000000000000000000006 for native gas token", - ) - token_b: str = Field( - ..., - description="The address of the second token to trade, e.g. 0x1234567890123456789012345678901234567890 for ERC20 token", - ) - fee: str = Field( - ..., - description="The fee to charge for trades, denominated in hundredths of a bip (i.e. 1e-6). Acceptable fee values are 100, 500, 3000, and 10000.", - ) - - -def uniswap_v3_create_pool(wallet: Wallet, token_a: str, token_b: str, fee: str) -> str: - """Create a Uniswap v3 pool for trading 2 tokens, one of which can be the native gas token. - - Args: - wallet (Wallet): The wallet to create the pool from. - token_a (str): The address of the first token to trade, e.g. 0x4200000000000000000000000000000000000006 for native gas token - token_b (str): The address of the second token to trade, e.g. 0x1234567890123456789012345678901234567890 for ERC20 token - fee (str): The fee to charge for trades, denominated in hundredths of a bip (i.e. 1e-6). - - Returns: - str: A message containing the pool creation details. - - """ - factory_address = get_contract_address(wallet.network_id) - - pool = wallet.invoke_contract( - contract_address=factory_address, - method="createPool", - abi=UNISWAP_V3_FACTORY_ABI, - args={ - "tokenA": token_a, - "tokenB": token_b, - "fee": fee, - }, - ).wait() - return f"Created pool for {token_a} and {token_b} with fee {fee} on network {wallet.network_id}.\nTransaction hash for the pool creation: {pool.transaction.transaction_hash}\nTransaction link for the pool creation: {pool.transaction.transaction_link}" - - -class UniswapV3CreatePoolAction(CdpAction): - """Uniswap V3 create pool action.""" - - name: str = "uniswap_v3_create_pool" - description: str = UNISWAP_V3_CREATE_POOL_PROMPT - args_schema: type[BaseModel] | None = UniswapV3CreatePoolInput - func: Callable[..., str] = uniswap_v3_create_pool diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool.py b/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool.py deleted file mode 100644 index 68b9f6d88..000000000 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool.py +++ /dev/null @@ -1,70 +0,0 @@ -from collections.abc import Callable - -from cdp import SmartContract -from pydantic import BaseModel, Field - -from cdp_agentkit_core.actions.cdp_action import CdpAction -from cdp_agentkit_core.actions.uniswap_v3.constants import ( - UNISWAP_V3_FACTORY_ABI, - get_contract_address, -) - -UNISWAP_V3_GET_POOL_PROMPT = """ -This tool will get the pool contract address for Uniswap V3 pools that have been previously created. It takes in the networkId, the two token addresses, with the value 0x4200000000000000000000000000000000000006 for native gas token and a value like 0x1234567890123456789012345678901234567890 for ERC20 token. It also takes in the pool fee, which is denominated in hundredths of a bip (i.e. 1e-6). Acceptable fee values are 100, 500, 3000, and 10000. Supported networks are Base Sepolia, Base Mainnet, Ethereum Mainnet, Polygon Mainnet, and Arbitrum Mainnet. -""" - - -class UniswapV3GetPoolInput(BaseModel): - """Input argument schema for get pool action.""" - - network_id: str = Field( - ..., - description="The network ID of the network to get the pool on.", - ) - token_a: str = Field( - ..., - description="The address of the first token to trade, e.g. 0x4200000000000000000000000000000000000006 for native gas token", - ) - token_b: str = Field( - ..., - description="The address of the second token to trade, e.g. 0x1234567890123456789012345678901234567890 for ERC20 token", - ) - fee: str = Field( - ..., - description="The fee to charge for trades, denominated in hundredths of a bip (i.e. 1e-6). Acceptable fee values are 100, 500, 3000, and 10000.", - ) - - -def uniswap_v3_get_pool(network_id: str, token_a: str, token_b: str, fee: str) -> str: - """Get the pool contract address for Uniswap V3 pools that have been created. - - Args: - network_id (str): The network ID of the network to get the pool on. - token_a (str): The address of the first token to trade, e.g. 0x4200000000000000000000000000000000000006 for native gas token - token_b (str): The address of the second token to trade, e.g. 0x1234567890123456789012345678901234567890 for ERC20 token - fee (str): The fee to charge for trades, denominated in hundredths of a bip (i.e. 1e-6). - - Returns: - str: A message containing the pool creation details. - - """ - factory_address = get_contract_address(network_id) - - pool_address = SmartContract.read( - network_id=network_id, - contract_address=factory_address, - method="getPool", - abi=UNISWAP_V3_FACTORY_ABI, - args={"tokenA": token_a, "tokenB": token_b, "fee": fee}, - ) - - return f"Pool contract address for {token_a} and {token_b} with fee {fee} on network {network_id} is {pool_address}." - - -class UniswapV3GetPoolAction(CdpAction): - """Uniswap V3 get pool action.""" - - name: str = "uniswap_v3_get_pool" - description: str = UNISWAP_V3_GET_POOL_PROMPT - args_schema: type[BaseModel] | None = UniswapV3GetPoolInput - func: Callable[..., str] = uniswap_v3_get_pool diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_liquidity.py b/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_liquidity.py deleted file mode 100644 index 81733b224..000000000 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_liquidity.py +++ /dev/null @@ -1,57 +0,0 @@ -from collections.abc import Callable - -from cdp import SmartContract -from pydantic import BaseModel, Field - -from cdp_agentkit_core.actions.cdp_action import CdpAction -from cdp_agentkit_core.actions.uniswap_v3.constants import ( - UNISWAP_V3_POOL_ABI, -) - -UNISWAP_V3_GET_POOL_LIQUIDITY_PROMPT = """ -This tool will get the liquidity for Uniswap V3 pools that have been previously created. It takes in the networkId and the pool contract address. Supported networks are Base Sepolia, Base Mainnet, Ethereum Mainnet, Polygon Mainnet, and Arbitrum Mainnet. -""" - - -class UniswapV3GetPoolLiquidityInput(BaseModel): - """Input argument schema for get pool liquidity action.""" - - network_id: str = Field( - ..., - description="The network ID of the network to get the pool on.", - ) - pool_contract_address: str = Field( - ..., - description="The contract address of the pool to get the liquidity for.", - ) - - -def uniswap_v3_get_pool_liquidity(network_id: str, pool_contract_address: str) -> str: - """Get the liquidity for Uniswap V3 pools that have been created. - - Args: - network_id (str): The network ID of the network to get the pool on. - pool_contract_address (str): The contract address of the pool to get the liquidity for. - - Returns: - str: A message containing the liquidity for the pool. - - """ - liquidity = SmartContract.read( - network_id=network_id, - contract_address=pool_contract_address, - method="liquidity", - abi=UNISWAP_V3_POOL_ABI, - args={}, - ) - - return f"Liquidity for pool {pool_contract_address} is {liquidity}." - - -class UniswapV3GetPoolLiquidityAction(CdpAction): - """Uniswap V3 get pool liquidity action.""" - - name: str = "uniswap_v3_get_pool_liquidity" - description: str = UNISWAP_V3_GET_POOL_LIQUIDITY_PROMPT - args_schema: type[BaseModel] | None = UniswapV3GetPoolLiquidityInput - func: Callable[..., str] = uniswap_v3_get_pool_liquidity diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_observe.py b/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_observe.py deleted file mode 100644 index 4aaa83393..000000000 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_observe.py +++ /dev/null @@ -1,67 +0,0 @@ -from collections.abc import Callable - -from cdp import SmartContract -from pydantic import BaseModel, Field - -from cdp_agentkit_core.actions.cdp_action import CdpAction -from cdp_agentkit_core.actions.uniswap_v3.constants import ( - UNISWAP_V3_POOL_ABI, -) - -UNISWAP_V3_GET_POOL_OBSERVE_PROMPT = """ -This tool will get the observation details for Uniswap V3 pools that have been previously created. It takes in a network ID, pool contract address, and list of secondsAgo values and returns the tickCumulative and secondsPerLiquidityCumulativeX128 for each secondsAgo value. -The tickCumulative is the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp. -The secondsPerLiquidityCumulativesX128 is the seconds per in range liquidity for the life of the pool as of the observation timestamp. -Supported networks are Base Sepolia, Base Mainnet, Ethereum Mainnet, Polygon Mainnet, and Arbitrum Mainnet. -""" - - -class UniswapV3GetPoolObserveInput(BaseModel): - """Input argument schema for get pool observe action.""" - - network_id: str = Field( - ..., - description="The network ID of the network to get the pool on.", - ) - pool_contract_address: str = Field( - ..., - description="The contract address of the pool to get the slot0 for.", - ) - seconds_ago: list[str] = Field( - ..., - description="The list of seconds ago values to get the observation for. The seconds ago value is the number of seconds ago from the current block timestamp to get the observation for and is provided as a string.", - ) - - -def uniswap_v3_get_pool_observe( - network_id: str, pool_contract_address: str, seconds_ago: list[str] -) -> str: - """Get the observation for Uniswap V3 pools that have been created. - - Args: - network_id (str): The network ID of the network to get the pool on. - pool_contract_address (str): The contract address of the pool to get the observation for. - seconds_ago (List[str]): The list of seconds ago values to get the observation for. The seconds ago value is the number of seconds ago from the current block timestamp to get the observation for and is provided as a string. - - Returns: - str: A message containing the observation details for the pool. - - """ - observations = SmartContract.read( - network_id=network_id, - contract_address=pool_contract_address, - method="observe", - abi=UNISWAP_V3_POOL_ABI, - args={"secondsAgos": seconds_ago}, - ) - - return f"Observations for pool {pool_contract_address} are {observations}." - - -class UniswapV3GetPoolObserveAction(CdpAction): - """Uniswap V3 get pool observe action.""" - - name: str = "uniswap_v3_get_pool_observe" - description: str = UNISWAP_V3_GET_POOL_OBSERVE_PROMPT - args_schema: type[BaseModel] | None = UniswapV3GetPoolObserveInput - func: Callable[..., str] = uniswap_v3_get_pool_observe diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_slot0.py b/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_slot0.py deleted file mode 100644 index bf73360f0..000000000 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/uniswap_v3/get_pool_slot0.py +++ /dev/null @@ -1,62 +0,0 @@ -from collections.abc import Callable - -from cdp import SmartContract -from pydantic import BaseModel, Field - -from cdp_agentkit_core.actions.cdp_action import CdpAction -from cdp_agentkit_core.actions.uniswap_v3.constants import ( - UNISWAP_V3_POOL_ABI, -) - -UNISWAP_V3_GET_POOL_SLOT0_PROMPT = """ -This tool will get the slot0 for Uniswap V3 pools. It takes in a networkId and pool contract address. The slot0 contains the sqrtPriceX96, tick, observationIndex, observationCardinality, observationCardinalityNext, feeProtocol, and unlocked. -The sqrtPriceX96 is the current price of the pool as a sqrt(token1/token0) Q64.96 value. -The tick is the current tick, based on the last transition that was run. This value may not always equal SqrtTickMath getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick boundary. -The observationIndex is the index of the last oracle observation. The observationCardinality is the maximum number of observations stored. -The observationCardinalityNext is the next maximum number of observations. The feeProtocol is the current fee as a percentage of the swap fee taken on withdrawal. -The unlocked is whether the pool is currently locked to reentrancy. Supported networks are Base Sepolia, Base Mainnet, Ethereum Mainnet, Polygon Mainnet, and Arbitrum Mainnet. -""" - - -class UniswapV3GetPoolSlot0Input(BaseModel): - """Input argument schema for get pool slot0 action.""" - - network_id: str = Field( - ..., - description="The network ID of the network to get the pool on.", - ) - pool_contract_address: str = Field( - ..., - description="The contract address of the pool to get the slot0 for.", - ) - - -def uniswap_v3_get_pool_slot0(network_id: str, pool_contract_address: str) -> str: - """Get the slot0 for Uniswap V3 pools that have been created. - - Args: - network_id (str): The network ID of the network to get the pool on. - pool_contract_address (str): The contract address of the pool to get the liquidity for. - - Returns: - str: A message containing the slot0 details for the pool. - - """ - slot0 = SmartContract.read( - network_id=network_id, - contract_address=pool_contract_address, - method="slot0", - abi=UNISWAP_V3_POOL_ABI, - args={}, - ) - - return f"Slot0 for pool {pool_contract_address} is {slot0}." - - -class UniswapV3GetPoolSlot0Action(CdpAction): - """Uniswap V3 get pool slot0 action.""" - - name: str = "uniswap_v3_get_pool_slot0" - description: str = UNISWAP_V3_GET_POOL_SLOT0_PROMPT - args_schema: type[BaseModel] | None = UniswapV3GetPoolSlot0Input - func: Callable[..., str] = uniswap_v3_get_pool_slot0 diff --git a/cdp-agentkit-core/tests/actions/uniswap_v3/test_create_pool.py b/cdp-agentkit-core/tests/actions/uniswap_v3/test_create_pool.py deleted file mode 100644 index d57f0c1f2..000000000 --- a/cdp-agentkit-core/tests/actions/uniswap_v3/test_create_pool.py +++ /dev/null @@ -1,85 +0,0 @@ -from unittest.mock import patch - -import pytest - -from cdp_agentkit_core.actions.uniswap_v3.constants import UNISWAP_V3_FACTORY_ABI -from cdp_agentkit_core.actions.uniswap_v3.create_pool import ( - UniswapV3CreatePoolInput, - uniswap_v3_create_pool, -) - -MOCK_TOKEN_A = "0x4200000000000000000000000000000000000006" -MOCK_TOKEN_B = "0x1234567890123456789012345678901234567890" -MOCK_FEE = "3000" - - -def test_create_pool_input_model_valid(): - """Test that CreatePoolInput accepts valid parameters.""" - input_model = UniswapV3CreatePoolInput( - token_a=MOCK_TOKEN_A, - token_b=MOCK_TOKEN_B, - fee=MOCK_FEE, - ) - - assert input_model.token_a == MOCK_TOKEN_A - assert input_model.token_b == MOCK_TOKEN_B - assert input_model.fee == MOCK_FEE - - -def test_create_pool_input_model_missing_params(): - """Test that CreatePoolInput raises error when params are missing.""" - with pytest.raises(ValueError): - UniswapV3CreatePoolInput() - - -def test_create_pool_success(wallet_factory, contract_invocation_factory): - """Test successful pool creation with valid parameters.""" - mock_wallet = wallet_factory() - mock_contract_instance = contract_invocation_factory() - - 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 = uniswap_v3_create_pool(mock_wallet, MOCK_TOKEN_A, MOCK_TOKEN_B, MOCK_FEE) - - expected_response = f"Created pool for {MOCK_TOKEN_A} and {MOCK_TOKEN_B} with fee {MOCK_FEE} on network {mock_wallet.network_id}.\nTransaction hash for the pool creation: {mock_contract_instance.transaction.transaction_hash}\nTransaction link for the pool creation: {mock_contract_instance.transaction.transaction_link}" - assert action_response == expected_response - - mock_invoke.assert_called_once_with( - contract_address="0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", - method="createPool", - abi=UNISWAP_V3_FACTORY_ABI, - args={ - "tokenA": MOCK_TOKEN_A, - "tokenB": MOCK_TOKEN_B, - "fee": MOCK_FEE, - }, - ) - mock_contract_wait.assert_called_once_with() - - -def test_create_pool_api_error(wallet_factory): - """Test create_pool when API error occurs.""" - mock_wallet = wallet_factory() - - with patch.object( - mock_wallet, "invoke_contract", side_effect=Exception("API error") - ) as mock_invoke: - with pytest.raises(Exception, match="API error"): - uniswap_v3_create_pool(mock_wallet, MOCK_TOKEN_A, MOCK_TOKEN_B, MOCK_FEE) - - mock_invoke.assert_called_once_with( - contract_address="0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", - method="createPool", - abi=UNISWAP_V3_FACTORY_ABI, - args={ - "tokenA": MOCK_TOKEN_A, - "tokenB": MOCK_TOKEN_B, - "fee": MOCK_FEE, - }, - ) diff --git a/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_liquidity.py b/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_liquidity.py deleted file mode 100644 index cae13cd77..000000000 --- a/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_liquidity.py +++ /dev/null @@ -1,68 +0,0 @@ -from unittest.mock import patch - -import pytest - -from cdp_agentkit_core.actions.uniswap_v3.constants import UNISWAP_V3_POOL_ABI -from cdp_agentkit_core.actions.uniswap_v3.get_pool_liquidity import ( - UniswapV3GetPoolLiquidityInput, - uniswap_v3_get_pool_liquidity, -) - -MOCK_POOL_ADDRESS = "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24" -MOCK_NETWORK_ID = "base-sepolia" -MOCK_LIQUIDITY = "1000000000000000000" - - -def test_get_pool_liquidity_input_model_valid(): - """Test that GetPoolLiquidityInput accepts valid parameters.""" - input_model = UniswapV3GetPoolLiquidityInput( - network_id=MOCK_NETWORK_ID, - pool_contract_address=MOCK_POOL_ADDRESS, - ) - - assert input_model.network_id == MOCK_NETWORK_ID - assert input_model.pool_contract_address == MOCK_POOL_ADDRESS - - -def test_get_pool_liquidity_input_model_missing_params(): - """Test that GetPoolLiquidityInput raises error when params are missing.""" - with pytest.raises(ValueError): - UniswapV3GetPoolLiquidityInput() - - -def test_get_pool_liquidity_success(): - """Test successful liquidity retrieval with valid parameters.""" - with patch( - "cdp_agentkit_core.actions.uniswap_v3.get_pool_liquidity.SmartContract.read", - return_value=MOCK_LIQUIDITY, - ) as mock_read: - response = uniswap_v3_get_pool_liquidity(MOCK_NETWORK_ID, MOCK_POOL_ADDRESS) - - expected_response = f"Liquidity for pool {MOCK_POOL_ADDRESS} is {MOCK_LIQUIDITY}." - assert response == expected_response - - mock_read.assert_called_once_with( - network_id=MOCK_NETWORK_ID, - contract_address=MOCK_POOL_ADDRESS, - method="liquidity", - abi=UNISWAP_V3_POOL_ABI, - args={}, - ) - - -def test_get_pool_liquidity_api_error(): - """Test get_pool_liquidity when API error occurs.""" - with patch( - "cdp_agentkit_core.actions.uniswap_v3.get_pool_liquidity.SmartContract.read", - side_effect=Exception("API error"), - ) as mock_read: - with pytest.raises(Exception, match="API error"): - uniswap_v3_get_pool_liquidity(MOCK_NETWORK_ID, MOCK_POOL_ADDRESS) - - mock_read.assert_called_once_with( - network_id=MOCK_NETWORK_ID, - contract_address=MOCK_POOL_ADDRESS, - method="liquidity", - abi=UNISWAP_V3_POOL_ABI, - args={}, - ) diff --git a/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_observe.py b/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_observe.py deleted file mode 100644 index e15f8c7ba..000000000 --- a/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_observe.py +++ /dev/null @@ -1,74 +0,0 @@ -from unittest.mock import patch - -import pytest - -from cdp_agentkit_core.actions.uniswap_v3.constants import UNISWAP_V3_POOL_ABI -from cdp_agentkit_core.actions.uniswap_v3.get_pool_observe import ( - UniswapV3GetPoolObserveInput, - uniswap_v3_get_pool_observe, -) - -MOCK_POOL_ADDRESS = "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24" -MOCK_NETWORK_ID = "base-sepolia" -MOCK_SECONDS_AGO = ["60", "120"] -MOCK_OBSERVATIONS = ( - ["1000000", "2000000"], # tickCumulatives - ["500000", "1000000"], # secondsPerLiquidityCumulativeX128s -) - - -def test_get_pool_observe_input_model_valid(): - """Test that GetPoolObserveInput accepts valid parameters.""" - input_model = UniswapV3GetPoolObserveInput( - network_id=MOCK_NETWORK_ID, - pool_contract_address=MOCK_POOL_ADDRESS, - seconds_ago=MOCK_SECONDS_AGO, - ) - - assert input_model.network_id == MOCK_NETWORK_ID - assert input_model.pool_contract_address == MOCK_POOL_ADDRESS - assert input_model.seconds_ago == MOCK_SECONDS_AGO - - -def test_get_pool_observe_input_model_missing_params(): - """Test that GetPoolObserveInput raises error when params are missing.""" - with pytest.raises(ValueError): - UniswapV3GetPoolObserveInput() - - -def test_get_pool_observe_success(): - """Test successful observation retrieval with valid parameters.""" - with patch( - "cdp_agentkit_core.actions.uniswap_v3.get_pool_observe.SmartContract.read", - return_value=MOCK_OBSERVATIONS, - ) as mock_read: - response = uniswap_v3_get_pool_observe(MOCK_NETWORK_ID, MOCK_POOL_ADDRESS, MOCK_SECONDS_AGO) - - expected_response = f"Observations for pool {MOCK_POOL_ADDRESS} are {MOCK_OBSERVATIONS}." - assert response == expected_response - - mock_read.assert_called_once_with( - network_id=MOCK_NETWORK_ID, - contract_address=MOCK_POOL_ADDRESS, - method="observe", - abi=UNISWAP_V3_POOL_ABI, - args={"secondsAgos": MOCK_SECONDS_AGO}, - ) - - -def test_get_pool_observe_api_error(): - """Test get_pool_observe when API error occurs.""" - with patch( - "cdp_agentkit_core.actions.uniswap_v3.get_pool_observe.SmartContract.read", - side_effect=Exception("API error"), - ) as mock_read: - with pytest.raises(Exception, match="API error"): - uniswap_v3_get_pool_observe(MOCK_NETWORK_ID, MOCK_POOL_ADDRESS, MOCK_SECONDS_AGO) - - mock_read.assert_called_once_with( - network_id=MOCK_NETWORK_ID, - contract_address=MOCK_POOL_ADDRESS, - method="observe", - abi=UNISWAP_V3_POOL_ABI, - args={"secondsAgos": MOCK_SECONDS_AGO}, - ) diff --git a/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_slot0.py b/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_slot0.py deleted file mode 100644 index f30beea9b..000000000 --- a/cdp-agentkit-core/tests/actions/uniswap_v3/test_get_pool_slot0.py +++ /dev/null @@ -1,76 +0,0 @@ -from unittest.mock import patch - -import pytest - -from cdp_agentkit_core.actions.uniswap_v3.constants import UNISWAP_V3_POOL_ABI -from cdp_agentkit_core.actions.uniswap_v3.get_pool_slot0 import ( - UniswapV3GetPoolSlot0Input, - uniswap_v3_get_pool_slot0, -) - -MOCK_POOL_ADDRESS = "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24" -MOCK_NETWORK_ID = "base-sepolia" -MOCK_SLOT0_RESPONSE = ( - "1234567890", # sqrtPriceX96 - "100", # tick - "1", # observationIndex - "50", # observationCardinality - "100", # observationCardinalityNext - "0", # feeProtocol - True, # unlocked -) - - -def test_get_pool_slot0_input_model_valid(): - """Test that GetPoolSlot0Input accepts valid parameters.""" - input_model = UniswapV3GetPoolSlot0Input( - network_id=MOCK_NETWORK_ID, - pool_contract_address=MOCK_POOL_ADDRESS, - ) - - assert input_model.network_id == MOCK_NETWORK_ID - assert input_model.pool_contract_address == MOCK_POOL_ADDRESS - - -def test_get_pool_slot0_input_model_missing_params(): - """Test that GetPoolSlot0Input raises error when params are missing.""" - with pytest.raises(ValueError): - UniswapV3GetPoolSlot0Input() - - -def test_get_pool_slot0_success(): - """Test successful slot0 retrieval with valid parameters.""" - with patch( - "cdp_agentkit_core.actions.uniswap_v3.get_pool_slot0.SmartContract.read", - return_value=MOCK_SLOT0_RESPONSE, - ) as mock_read: - response = uniswap_v3_get_pool_slot0(MOCK_NETWORK_ID, MOCK_POOL_ADDRESS) - - expected_response = f"Slot0 for pool {MOCK_POOL_ADDRESS} is {MOCK_SLOT0_RESPONSE}." - assert response == expected_response - - mock_read.assert_called_once_with( - network_id=MOCK_NETWORK_ID, - contract_address=MOCK_POOL_ADDRESS, - method="slot0", - abi=UNISWAP_V3_POOL_ABI, - args={}, - ) - - -def test_get_pool_slot0_api_error(): - """Test get_pool_slot0 when API error occurs.""" - with patch( - "cdp_agentkit_core.actions.uniswap_v3.get_pool_slot0.SmartContract.read", - side_effect=Exception("API error"), - ) as mock_read: - with pytest.raises(Exception, match="API error"): - uniswap_v3_get_pool_slot0(MOCK_NETWORK_ID, MOCK_POOL_ADDRESS) - - mock_read.assert_called_once_with( - network_id=MOCK_NETWORK_ID, - contract_address=MOCK_POOL_ADDRESS, - method="slot0", - abi=UNISWAP_V3_POOL_ABI, - args={}, - ) diff --git a/cdp-langchain/CHANGELOG.md b/cdp-langchain/CHANGELOG.md index dd341cc99..ba11e9607 100644 --- a/cdp-langchain/CHANGELOG.md +++ b/cdp-langchain/CHANGELOG.md @@ -4,9 +4,6 @@ ### Added -- Added `uniswap_v3_create_pool` action to the cdp toolkit. -- Added `uniswap_v3_get_pool`, `uniswap_v3_get_pool_observe`, `uniswap_v3_get_pool_slot0`, and `uniswap_v3_get_pool_liquidity` actions to the cdp toolkit. - ## [0.0.1] - 2024-11-04 ### Added diff --git a/cdp-langchain/cdp_langchain/agent_toolkits/cdp_toolkit.py b/cdp-langchain/cdp_langchain/agent_toolkits/cdp_toolkit.py index dd24148cc..7fa7493b3 100644 --- a/cdp-langchain/cdp_langchain/agent_toolkits/cdp_toolkit.py +++ b/cdp-langchain/cdp_langchain/agent_toolkits/cdp_toolkit.py @@ -60,11 +60,6 @@ class CdpToolkit(BaseToolkit): mint_nft deploy_nft register_basename - uniswap_v3_create_pool - uniswap_v3_get_pool - uniswap_v3_get_pool_observe - uniswap_v3_get_pool_slot0 - uniswap_v3_get_pool_liquidity Use within an agent: .. code-block:: python