intentkit 0.6.13.dev2__py3-none-any.whl → 0.8.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of intentkit might be problematic. Click here for more details.
- intentkit/__init__.py +1 -1
- intentkit/abstracts/agent.py +4 -5
- intentkit/abstracts/engine.py +5 -5
- intentkit/abstracts/graph.py +14 -7
- intentkit/abstracts/skill.py +6 -144
- intentkit/abstracts/twitter.py +4 -5
- intentkit/clients/__init__.py +5 -2
- intentkit/clients/cdp.py +101 -141
- intentkit/clients/twitter.py +83 -62
- intentkit/clients/web3.py +29 -0
- intentkit/config/config.py +8 -5
- intentkit/core/agent.py +472 -195
- intentkit/core/asset.py +253 -0
- intentkit/core/chat.py +51 -0
- intentkit/core/client.py +1 -1
- intentkit/core/credit.py +460 -130
- intentkit/core/engine.py +262 -233
- intentkit/core/node.py +15 -16
- intentkit/core/prompt.py +62 -28
- intentkit/core/scheduler.py +92 -0
- intentkit/core/statistics.py +168 -0
- intentkit/models/agent.py +1096 -949
- intentkit/models/agent_data.py +68 -38
- intentkit/models/agent_public.json +98 -0
- intentkit/models/agent_schema.json +54 -439
- intentkit/models/app_setting.py +96 -33
- intentkit/models/chat.py +74 -27
- intentkit/models/conversation.py +8 -8
- intentkit/models/credit.py +362 -74
- intentkit/models/db.py +26 -8
- intentkit/models/db_mig.py +2 -2
- intentkit/models/llm.csv +28 -0
- intentkit/models/llm.py +185 -350
- intentkit/models/redis.py +6 -4
- intentkit/models/skill.py +186 -72
- intentkit/models/skills.csv +174 -0
- intentkit/models/user.py +82 -24
- intentkit/skills/acolyt/__init__.py +2 -9
- intentkit/skills/acolyt/ask.py +3 -4
- intentkit/skills/acolyt/base.py +4 -9
- intentkit/skills/acolyt/schema.json +4 -3
- intentkit/skills/aixbt/__init__.py +2 -13
- intentkit/skills/aixbt/base.py +1 -7
- intentkit/skills/aixbt/projects.py +14 -15
- intentkit/skills/aixbt/schema.json +4 -4
- intentkit/skills/allora/__init__.py +2 -9
- intentkit/skills/allora/base.py +4 -9
- intentkit/skills/allora/price.py +3 -4
- intentkit/skills/allora/schema.json +3 -2
- intentkit/skills/base.py +248 -85
- intentkit/skills/basename/__init__.py +51 -0
- intentkit/skills/basename/base.py +11 -0
- intentkit/skills/basename/basename.svg +11 -0
- intentkit/skills/basename/schema.json +58 -0
- intentkit/skills/carv/__init__.py +115 -121
- intentkit/skills/carv/base.py +184 -185
- intentkit/skills/carv/fetch_news.py +3 -3
- intentkit/skills/carv/onchain_query.py +4 -4
- intentkit/skills/carv/schema.json +134 -137
- intentkit/skills/carv/token_info_and_price.py +5 -5
- intentkit/skills/casino/README.md +254 -0
- intentkit/skills/casino/__init__.py +86 -0
- intentkit/skills/casino/base.py +17 -0
- intentkit/skills/casino/casino.png +0 -0
- intentkit/skills/casino/deck_draw.py +127 -0
- intentkit/skills/casino/deck_shuffle.py +118 -0
- intentkit/skills/casino/dice_roll.py +100 -0
- intentkit/skills/casino/schema.json +77 -0
- intentkit/skills/casino/utils.py +107 -0
- intentkit/skills/cdp/__init__.py +22 -84
- intentkit/skills/cdp/base.py +1 -7
- intentkit/skills/cdp/schema.json +11 -314
- intentkit/skills/chainlist/__init__.py +2 -7
- intentkit/skills/chainlist/base.py +1 -7
- intentkit/skills/chainlist/chain_lookup.py +18 -18
- intentkit/skills/chainlist/schema.json +3 -5
- intentkit/skills/common/__init__.py +2 -9
- intentkit/skills/common/base.py +1 -7
- intentkit/skills/common/current_time.py +1 -2
- intentkit/skills/common/schema.json +2 -2
- intentkit/skills/cookiefun/__init__.py +6 -9
- intentkit/skills/cookiefun/base.py +2 -7
- intentkit/skills/cookiefun/get_account_details.py +7 -7
- intentkit/skills/cookiefun/get_account_feed.py +19 -19
- intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
- intentkit/skills/cookiefun/get_sectors.py +3 -3
- intentkit/skills/cookiefun/schema.json +1 -3
- intentkit/skills/cookiefun/search_accounts.py +9 -9
- intentkit/skills/cryptocompare/__init__.py +7 -24
- intentkit/skills/cryptocompare/api.py +2 -3
- intentkit/skills/cryptocompare/base.py +11 -25
- intentkit/skills/cryptocompare/fetch_news.py +4 -5
- intentkit/skills/cryptocompare/fetch_price.py +6 -7
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
- intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
- intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
- intentkit/skills/cryptocompare/schema.json +3 -3
- intentkit/skills/cryptopanic/__init__.py +7 -10
- intentkit/skills/cryptopanic/base.py +51 -55
- intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
- intentkit/skills/cryptopanic/schema.json +105 -103
- intentkit/skills/dapplooker/__init__.py +2 -9
- intentkit/skills/dapplooker/base.py +4 -9
- intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
- intentkit/skills/dapplooker/schema.json +3 -5
- intentkit/skills/defillama/__init__.py +24 -74
- intentkit/skills/defillama/api.py +6 -9
- intentkit/skills/defillama/base.py +11 -21
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
- intentkit/skills/defillama/coins/fetch_block.py +6 -8
- intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
- intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
- intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
- intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
- intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
- intentkit/skills/defillama/config/chains.py +1 -3
- intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
- intentkit/skills/defillama/schema.json +5 -1
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
- intentkit/skills/defillama/tests/api_integration.test.py +1 -1
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
- intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
- intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
- intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
- intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
- intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
- intentkit/skills/defillama/yields/fetch_pools.py +26 -30
- intentkit/skills/dexscreener/README.md +154 -0
- intentkit/skills/dexscreener/__init__.py +97 -93
- intentkit/skills/dexscreener/base.py +125 -133
- intentkit/skills/dexscreener/get_pair_info.py +158 -0
- intentkit/skills/dexscreener/get_token_pairs.py +165 -0
- intentkit/skills/dexscreener/get_tokens_info.py +212 -0
- intentkit/skills/dexscreener/model/search_token_response.py +80 -82
- intentkit/skills/dexscreener/schema.json +91 -48
- intentkit/skills/dexscreener/search_token.py +182 -321
- intentkit/skills/dexscreener/utils.py +420 -0
- intentkit/skills/dune_analytics/__init__.py +7 -9
- intentkit/skills/dune_analytics/base.py +48 -52
- intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
- intentkit/skills/dune_analytics/schema.json +104 -99
- intentkit/skills/elfa/__init__.py +5 -18
- intentkit/skills/elfa/base.py +10 -14
- intentkit/skills/elfa/mention.py +19 -21
- intentkit/skills/elfa/schema.json +3 -2
- intentkit/skills/elfa/stats.py +4 -4
- intentkit/skills/elfa/tokens.py +12 -12
- intentkit/skills/elfa/utils.py +26 -28
- intentkit/skills/enso/__init__.py +11 -31
- intentkit/skills/enso/base.py +50 -35
- intentkit/skills/enso/best_yield.py +16 -24
- intentkit/skills/enso/networks.py +6 -11
- intentkit/skills/enso/prices.py +11 -13
- intentkit/skills/enso/route.py +34 -38
- intentkit/skills/enso/schema.json +3 -2
- intentkit/skills/enso/tokens.py +29 -38
- intentkit/skills/enso/wallet.py +76 -191
- intentkit/skills/erc20/__init__.py +50 -0
- intentkit/skills/erc20/base.py +11 -0
- intentkit/skills/erc20/erc20.svg +5 -0
- intentkit/skills/erc20/schema.json +74 -0
- intentkit/skills/erc721/__init__.py +53 -0
- intentkit/skills/erc721/base.py +11 -0
- intentkit/skills/erc721/erc721.svg +5 -0
- intentkit/skills/erc721/schema.json +90 -0
- intentkit/skills/firecrawl/README.md +11 -5
- intentkit/skills/firecrawl/__init__.py +5 -18
- intentkit/skills/firecrawl/base.py +4 -11
- intentkit/skills/firecrawl/clear.py +4 -8
- intentkit/skills/firecrawl/crawl.py +19 -19
- intentkit/skills/firecrawl/query.py +4 -3
- intentkit/skills/firecrawl/schema.json +6 -8
- intentkit/skills/firecrawl/scrape.py +150 -40
- intentkit/skills/firecrawl/utils.py +50 -42
- intentkit/skills/github/__init__.py +2 -7
- intentkit/skills/github/base.py +1 -7
- intentkit/skills/github/github_search.py +1 -2
- intentkit/skills/github/schema.json +3 -4
- intentkit/skills/heurist/__init__.py +8 -27
- intentkit/skills/heurist/base.py +4 -9
- intentkit/skills/heurist/image_generation_animagine_xl.py +12 -13
- intentkit/skills/heurist/image_generation_arthemy_comics.py +12 -13
- intentkit/skills/heurist/image_generation_arthemy_real.py +12 -13
- intentkit/skills/heurist/image_generation_braindance.py +12 -13
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +12 -13
- intentkit/skills/heurist/image_generation_flux_1_dev.py +12 -13
- intentkit/skills/heurist/image_generation_sdxl.py +12 -13
- intentkit/skills/heurist/schema.json +2 -2
- intentkit/skills/http/__init__.py +4 -15
- intentkit/skills/http/base.py +1 -7
- intentkit/skills/http/get.py +21 -16
- intentkit/skills/http/post.py +23 -18
- intentkit/skills/http/put.py +23 -18
- intentkit/skills/http/schema.json +4 -5
- intentkit/skills/lifi/__init__.py +8 -13
- intentkit/skills/lifi/base.py +1 -7
- intentkit/skills/lifi/schema.json +17 -8
- intentkit/skills/lifi/token_execute.py +36 -30
- intentkit/skills/lifi/token_quote.py +8 -10
- intentkit/skills/lifi/utils.py +104 -51
- intentkit/skills/moralis/__init__.py +6 -10
- intentkit/skills/moralis/api.py +6 -7
- intentkit/skills/moralis/base.py +5 -10
- intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
- intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
- intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
- intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
- intentkit/skills/moralis/schema.json +7 -2
- intentkit/skills/morpho/__init__.py +52 -0
- intentkit/skills/morpho/base.py +11 -0
- intentkit/skills/morpho/morpho.svg +12 -0
- intentkit/skills/morpho/schema.json +73 -0
- intentkit/skills/nation/__init__.py +4 -9
- intentkit/skills/nation/base.py +5 -10
- intentkit/skills/nation/nft_check.py +3 -4
- intentkit/skills/nation/schema.json +4 -3
- intentkit/skills/onchain.py +23 -0
- intentkit/skills/openai/__init__.py +17 -18
- intentkit/skills/openai/base.py +10 -14
- intentkit/skills/openai/dalle_image_generation.py +3 -8
- intentkit/skills/openai/gpt_avatar_generator.py +102 -0
- intentkit/skills/openai/gpt_image_generation.py +4 -8
- intentkit/skills/openai/gpt_image_mini_generator.py +91 -0
- intentkit/skills/openai/gpt_image_to_image.py +4 -8
- intentkit/skills/openai/image_to_text.py +3 -7
- intentkit/skills/openai/schema.json +34 -3
- intentkit/skills/portfolio/__init__.py +11 -35
- intentkit/skills/portfolio/base.py +33 -19
- intentkit/skills/portfolio/schema.json +3 -5
- intentkit/skills/portfolio/token_balances.py +21 -21
- intentkit/skills/portfolio/wallet_approvals.py +17 -18
- intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
- intentkit/skills/portfolio/wallet_history.py +31 -31
- intentkit/skills/portfolio/wallet_net_worth.py +13 -13
- intentkit/skills/portfolio/wallet_nfts.py +19 -19
- intentkit/skills/portfolio/wallet_profitability.py +18 -18
- intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
- intentkit/skills/portfolio/wallet_stats.py +3 -3
- intentkit/skills/portfolio/wallet_swaps.py +19 -19
- intentkit/skills/pyth/__init__.py +50 -0
- intentkit/skills/pyth/base.py +11 -0
- intentkit/skills/pyth/pyth.svg +6 -0
- intentkit/skills/pyth/schema.json +75 -0
- intentkit/skills/skills.toml +40 -0
- intentkit/skills/slack/__init__.py +5 -17
- intentkit/skills/slack/base.py +3 -9
- intentkit/skills/slack/get_channel.py +8 -8
- intentkit/skills/slack/get_message.py +9 -9
- intentkit/skills/slack/schedule_message.py +5 -5
- intentkit/skills/slack/schema.json +2 -2
- intentkit/skills/slack/send_message.py +3 -5
- intentkit/skills/supabase/__init__.py +7 -23
- intentkit/skills/supabase/base.py +9 -13
- intentkit/skills/supabase/delete_data.py +5 -6
- intentkit/skills/supabase/fetch_data.py +13 -14
- intentkit/skills/supabase/insert_data.py +5 -6
- intentkit/skills/supabase/invoke_function.py +7 -8
- intentkit/skills/supabase/schema.json +2 -3
- intentkit/skills/supabase/update_data.py +7 -8
- intentkit/skills/supabase/upsert_data.py +5 -6
- intentkit/skills/superfluid/__init__.py +53 -0
- intentkit/skills/superfluid/base.py +11 -0
- intentkit/skills/superfluid/schema.json +89 -0
- intentkit/skills/superfluid/superfluid.svg +6 -0
- intentkit/skills/system/__init__.py +7 -24
- intentkit/skills/system/add_autonomous_task.py +10 -12
- intentkit/skills/system/delete_autonomous_task.py +2 -2
- intentkit/skills/system/edit_autonomous_task.py +14 -18
- intentkit/skills/system/list_autonomous_tasks.py +3 -5
- intentkit/skills/system/read_agent_api_key.py +6 -4
- intentkit/skills/system/regenerate_agent_api_key.py +6 -4
- intentkit/skills/system/schema.json +6 -8
- intentkit/skills/tavily/__init__.py +3 -12
- intentkit/skills/tavily/base.py +4 -9
- intentkit/skills/tavily/schema.json +3 -5
- intentkit/skills/tavily/tavily_extract.py +2 -4
- intentkit/skills/tavily/tavily_search.py +4 -6
- intentkit/skills/token/__init__.py +5 -10
- intentkit/skills/token/base.py +7 -11
- intentkit/skills/token/erc20_transfers.py +19 -19
- intentkit/skills/token/schema.json +3 -6
- intentkit/skills/token/token_analytics.py +3 -3
- intentkit/skills/token/token_price.py +13 -13
- intentkit/skills/token/token_search.py +9 -9
- intentkit/skills/twitter/__init__.py +11 -35
- intentkit/skills/twitter/base.py +23 -35
- intentkit/skills/twitter/follow_user.py +3 -7
- intentkit/skills/twitter/get_mentions.py +6 -13
- intentkit/skills/twitter/get_timeline.py +5 -13
- intentkit/skills/twitter/get_user_by_username.py +3 -7
- intentkit/skills/twitter/get_user_tweets.py +6 -14
- intentkit/skills/twitter/like_tweet.py +3 -7
- intentkit/skills/twitter/post_tweet.py +23 -12
- intentkit/skills/twitter/reply_tweet.py +21 -12
- intentkit/skills/twitter/retweet.py +3 -7
- intentkit/skills/twitter/schema.json +1 -0
- intentkit/skills/twitter/search_tweets.py +5 -13
- intentkit/skills/unrealspeech/__init__.py +2 -7
- intentkit/skills/unrealspeech/base.py +2 -8
- intentkit/skills/unrealspeech/schema.json +2 -5
- intentkit/skills/unrealspeech/text_to_speech.py +8 -8
- intentkit/skills/venice_audio/__init__.py +98 -106
- intentkit/skills/venice_audio/base.py +117 -121
- intentkit/skills/venice_audio/input.py +41 -41
- intentkit/skills/venice_audio/schema.json +151 -152
- intentkit/skills/venice_audio/venice_audio.py +38 -21
- intentkit/skills/venice_image/__init__.py +147 -154
- intentkit/skills/venice_image/api.py +138 -138
- intentkit/skills/venice_image/base.py +185 -192
- intentkit/skills/venice_image/config.py +33 -35
- intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
- intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
- intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
- intentkit/skills/venice_image/image_generation/image_generation_base.py +9 -9
- intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
- intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
- intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
- intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
- intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
- intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
- intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
- intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
- intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
- intentkit/skills/venice_image/schema.json +267 -267
- intentkit/skills/venice_image/utils.py +77 -78
- intentkit/skills/web_scraper/__init__.py +5 -18
- intentkit/skills/web_scraper/base.py +21 -7
- intentkit/skills/web_scraper/document_indexer.py +7 -6
- intentkit/skills/web_scraper/schema.json +2 -6
- intentkit/skills/web_scraper/scrape_and_index.py +15 -15
- intentkit/skills/web_scraper/utils.py +62 -63
- intentkit/skills/web_scraper/website_indexer.py +17 -19
- intentkit/skills/weth/__init__.py +49 -0
- intentkit/skills/weth/base.py +11 -0
- intentkit/skills/weth/schema.json +58 -0
- intentkit/skills/weth/weth.svg +6 -0
- intentkit/skills/wow/__init__.py +51 -0
- intentkit/skills/wow/base.py +11 -0
- intentkit/skills/wow/schema.json +89 -0
- intentkit/skills/wow/wow.svg +7 -0
- intentkit/skills/x402/__init__.py +61 -0
- intentkit/skills/x402/ask_agent.py +98 -0
- intentkit/skills/x402/base.py +99 -0
- intentkit/skills/x402/http_request.py +117 -0
- intentkit/skills/x402/schema.json +45 -0
- intentkit/skills/x402/x402.webp +0 -0
- intentkit/skills/xmtp/__init__.py +4 -15
- intentkit/skills/xmtp/base.py +61 -2
- intentkit/skills/xmtp/price.py +18 -13
- intentkit/skills/xmtp/schema.json +69 -71
- intentkit/skills/xmtp/swap.py +22 -25
- intentkit/skills/xmtp/transfer.py +71 -32
- intentkit/utils/chain.py +3 -3
- intentkit/utils/error.py +14 -1
- intentkit/utils/logging.py +2 -4
- intentkit/utils/s3.py +59 -7
- intentkit/utils/schema.py +100 -0
- intentkit/utils/slack_alert.py +7 -8
- {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/METADATA +14 -16
- intentkit-0.8.17.dist-info/RECORD +466 -0
- intentkit/abstracts/exception.py +0 -9
- intentkit/core/skill.py +0 -200
- intentkit/models/generator.py +0 -347
- intentkit/skills/cdp/get_balance.py +0 -110
- intentkit/skills/cdp/swap.py +0 -121
- intentkit/skills/moralis/tests/__init__.py +0 -0
- intentkit/skills/moralis/tests/test_wallet.py +0 -511
- intentkit-0.6.13.dev2.dist-info/RECORD +0 -409
- {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/WHEEL +0 -0
- {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/licenses/LICENSE +0 -0
intentkit/skills/cdp/swap.py
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
from typing import Optional, Type, Union
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel, Field
|
|
4
|
-
|
|
5
|
-
from intentkit.abstracts.skill import SkillStoreABC
|
|
6
|
-
from intentkit.clients import get_cdp_client
|
|
7
|
-
from intentkit.skills.cdp.base import CDPBaseTool
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class SwapInput(BaseModel):
|
|
11
|
-
"""Input for Swap tool."""
|
|
12
|
-
|
|
13
|
-
from_token: str = Field(
|
|
14
|
-
description="The contract address of the token to swap from (e.g., '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' for USDC on Base)"
|
|
15
|
-
)
|
|
16
|
-
to_token: str = Field(
|
|
17
|
-
description="The contract address of the token to swap to (e.g., '0x4200000000000000000000000000000000000006' for WETH on Base)"
|
|
18
|
-
)
|
|
19
|
-
from_amount: Union[str, int] = Field(
|
|
20
|
-
description="The amount to swap from in smallest unit (e.g., 1000000 for 1 USDC with 6 decimals)"
|
|
21
|
-
)
|
|
22
|
-
slippage_bps: Optional[int] = Field(
|
|
23
|
-
default=100,
|
|
24
|
-
description="Maximum slippage in basis points (100 = 1%). Defaults to 100 (1%)",
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class Swap(CDPBaseTool):
|
|
29
|
-
"""Tool for swapping tokens using CDP wallet.
|
|
30
|
-
|
|
31
|
-
This tool uses the CDP API to execute token swaps on supported networks.
|
|
32
|
-
It wraps the swap functionality from the EVM account.
|
|
33
|
-
|
|
34
|
-
Attributes:
|
|
35
|
-
name: The name of the tool.
|
|
36
|
-
description: A description of what the tool does.
|
|
37
|
-
args_schema: The schema for the tool's input arguments.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
agent_id: str
|
|
41
|
-
skill_store: SkillStoreABC
|
|
42
|
-
|
|
43
|
-
name: str = "cdp_swap"
|
|
44
|
-
description: str = (
|
|
45
|
-
"This tool will swap tokens using the CDP wallet. "
|
|
46
|
-
"It supports swapping between any ERC-20 tokens on supported networks (Base and Ethereum). "
|
|
47
|
-
"You need to provide the contract addresses of both tokens and the amount to swap. "
|
|
48
|
-
"The amount should be in the smallest unit of the token (e.g., wei for ETH, or atomic units for ERC-20 tokens). "
|
|
49
|
-
"Common token addresses on Base: USDC=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, WETH=0x4200000000000000000000000000000000000006. "
|
|
50
|
-
"The tool will automatically handle gas estimation and transaction submission."
|
|
51
|
-
)
|
|
52
|
-
args_schema: Type[BaseModel] = SwapInput
|
|
53
|
-
|
|
54
|
-
async def _arun(
|
|
55
|
-
self,
|
|
56
|
-
from_token: str,
|
|
57
|
-
to_token: str,
|
|
58
|
-
from_amount: Union[str, int],
|
|
59
|
-
slippage_bps: Optional[int] = 100,
|
|
60
|
-
) -> str:
|
|
61
|
-
"""Async implementation of the tool to swap tokens.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
from_token (str): The contract address of the token to swap from.
|
|
65
|
-
to_token (str): The contract address of the token to swap to.
|
|
66
|
-
from_amount (Union[str, int]): The amount to swap from in smallest unit.
|
|
67
|
-
slippage_bps (Optional[int]): Maximum slippage in basis points. Defaults to 100 (1%).
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
str: A message containing the swap result or error message.
|
|
71
|
-
"""
|
|
72
|
-
try:
|
|
73
|
-
# Get CDP client and network information
|
|
74
|
-
cdp_client = await get_cdp_client(self.agent_id, self.skill_store)
|
|
75
|
-
provider = await cdp_client.get_wallet_provider()
|
|
76
|
-
provider_config = await cdp_client.get_provider_config()
|
|
77
|
-
network_id = provider_config.network_id
|
|
78
|
-
|
|
79
|
-
# Map network_id to the format expected by the swap API
|
|
80
|
-
network_mapping = {
|
|
81
|
-
"base-mainnet": "base",
|
|
82
|
-
"ethereum-mainnet": "ethereum",
|
|
83
|
-
}
|
|
84
|
-
api_network = network_mapping.get(network_id, network_id)
|
|
85
|
-
|
|
86
|
-
# Validate network is supported
|
|
87
|
-
supported_networks = ["base", "ethereum"]
|
|
88
|
-
if api_network not in supported_networks:
|
|
89
|
-
return f"Error: Network {api_network} is not supported for swaps. Supported networks: {', '.join(supported_networks)}"
|
|
90
|
-
|
|
91
|
-
# Get the EVM account
|
|
92
|
-
client = provider.get_client()
|
|
93
|
-
async with client:
|
|
94
|
-
account = await client.evm.get_account(provider.get_address())
|
|
95
|
-
|
|
96
|
-
# Import AccountSwapOptions here to avoid circular imports
|
|
97
|
-
from cdp.actions.evm.swap.types import AccountSwapOptions
|
|
98
|
-
|
|
99
|
-
# Create swap options
|
|
100
|
-
swap_options = AccountSwapOptions(
|
|
101
|
-
network=api_network,
|
|
102
|
-
from_token=from_token,
|
|
103
|
-
to_token=to_token,
|
|
104
|
-
from_amount=str(from_amount),
|
|
105
|
-
slippage_bps=slippage_bps,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
# Execute the swap
|
|
109
|
-
result = await account.swap(swap_options)
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
f"Swap executed successfully!\n"
|
|
113
|
-
f"Transaction hash: {result.transaction_hash}\n"
|
|
114
|
-
f"Swapped from {from_token} to {to_token}\n"
|
|
115
|
-
f"Amount: {from_amount} (smallest units)\n"
|
|
116
|
-
f"Network: {api_network}\n"
|
|
117
|
-
f"Slippage tolerance: {slippage_bps} basis points ({slippage_bps / 100 if slippage_bps else 0}%)"
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
except Exception as e:
|
|
121
|
-
return f"Error executing swap: {e!s}"
|
|
File without changes
|
|
@@ -1,511 +0,0 @@
|
|
|
1
|
-
"""Tests for the Moralis Wallet Portfolio skills."""
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import json
|
|
5
|
-
import unittest
|
|
6
|
-
from unittest.mock import AsyncMock, MagicMock, patch
|
|
7
|
-
|
|
8
|
-
from intentkit.skills.moralis import (
|
|
9
|
-
FetchChainPortfolio,
|
|
10
|
-
FetchSolanaPortfolio,
|
|
11
|
-
FetchWalletPortfolio,
|
|
12
|
-
get_skills,
|
|
13
|
-
)
|
|
14
|
-
from intentkit.skills.moralis.api import (
|
|
15
|
-
fetch_moralis_data,
|
|
16
|
-
fetch_wallet_balances,
|
|
17
|
-
get_solana_portfolio,
|
|
18
|
-
)
|
|
19
|
-
from intentkit.skills.moralis.base import WalletBaseTool
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class DummyResponse:
|
|
23
|
-
"""Mock HTTP response for testing."""
|
|
24
|
-
|
|
25
|
-
def __init__(self, status_code, json_data):
|
|
26
|
-
self.status_code = status_code
|
|
27
|
-
self._json_data = json_data
|
|
28
|
-
self.text = json.dumps(json_data) if json_data else ""
|
|
29
|
-
|
|
30
|
-
def json(self):
|
|
31
|
-
return self._json_data
|
|
32
|
-
|
|
33
|
-
async def raise_for_status(self):
|
|
34
|
-
if self.status_code >= 400:
|
|
35
|
-
raise Exception(f"HTTP Error: {self.status_code}")
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class TestWalletBaseClass(unittest.TestCase):
|
|
39
|
-
"""Test the base wallet portfolio tool class."""
|
|
40
|
-
|
|
41
|
-
def setUp(self):
|
|
42
|
-
self.loop = asyncio.new_event_loop()
|
|
43
|
-
asyncio.set_event_loop(self.loop)
|
|
44
|
-
|
|
45
|
-
self.mock_skill_store = MagicMock()
|
|
46
|
-
|
|
47
|
-
def tearDown(self):
|
|
48
|
-
self.loop.close()
|
|
49
|
-
|
|
50
|
-
def test_base_class_init(self):
|
|
51
|
-
"""Test base class initialization."""
|
|
52
|
-
|
|
53
|
-
# Create a concrete subclass for testing
|
|
54
|
-
class TestTool(WalletBaseTool):
|
|
55
|
-
async def _arun(self, *args, **kwargs):
|
|
56
|
-
return "test"
|
|
57
|
-
|
|
58
|
-
tool = TestTool(
|
|
59
|
-
name="test_tool",
|
|
60
|
-
description="Test tool",
|
|
61
|
-
args_schema=MagicMock(),
|
|
62
|
-
api_key="test_key",
|
|
63
|
-
skill_store=self.mock_skill_store,
|
|
64
|
-
agent_id="test_agent",
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
self.assertEqual(tool.api_key, "test_key")
|
|
68
|
-
self.assertEqual(tool.agent_id, "test_agent")
|
|
69
|
-
self.assertEqual(tool.skill_store, self.mock_skill_store)
|
|
70
|
-
self.assertEqual(tool.category, "moralis")
|
|
71
|
-
|
|
72
|
-
def test_get_chain_name(self):
|
|
73
|
-
"""Test chain name conversion."""
|
|
74
|
-
|
|
75
|
-
class TestTool(WalletBaseTool):
|
|
76
|
-
async def _arun(self, *args, **kwargs):
|
|
77
|
-
return "test"
|
|
78
|
-
|
|
79
|
-
tool = TestTool(
|
|
80
|
-
name="test_tool",
|
|
81
|
-
description="Test tool",
|
|
82
|
-
args_schema=MagicMock(),
|
|
83
|
-
api_key="test_key",
|
|
84
|
-
skill_store=self.mock_skill_store,
|
|
85
|
-
agent_id="test_agent",
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
# Test with known chain IDs
|
|
89
|
-
self.assertEqual(tool._get_chain_name(1), "eth")
|
|
90
|
-
self.assertEqual(tool._get_chain_name(56), "bsc")
|
|
91
|
-
self.assertEqual(tool._get_chain_name(137), "polygon")
|
|
92
|
-
|
|
93
|
-
# Test with unknown chain ID
|
|
94
|
-
self.assertEqual(tool._get_chain_name(999999), "eth")
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
class TestAPIFunctions(unittest.IsolatedAsyncioTestCase):
|
|
98
|
-
"""Test the API interaction functions."""
|
|
99
|
-
|
|
100
|
-
async def test_fetch_moralis_data(self):
|
|
101
|
-
"""Test the base Moralis API function."""
|
|
102
|
-
with patch("httpx.AsyncClient") as MockClient:
|
|
103
|
-
client_instance = AsyncMock()
|
|
104
|
-
client_instance.get.return_value = DummyResponse(
|
|
105
|
-
200, {"success": True, "data": "test_data"}
|
|
106
|
-
)
|
|
107
|
-
MockClient.return_value.__aenter__.return_value = client_instance
|
|
108
|
-
|
|
109
|
-
result = await fetch_moralis_data(
|
|
110
|
-
"test_api_key", "test_endpoint", "0xAddress", 1
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
self.assertEqual(result, {"success": True, "data": "test_data"})
|
|
114
|
-
|
|
115
|
-
# Test error handling
|
|
116
|
-
client_instance.get.return_value = DummyResponse(404, None)
|
|
117
|
-
client_instance.get.return_value.raise_for_status = AsyncMock(
|
|
118
|
-
side_effect=Exception("HTTP error 404")
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
result = await fetch_moralis_data(
|
|
122
|
-
"test_api_key", "test_endpoint", "0xAddress", 1
|
|
123
|
-
)
|
|
124
|
-
self.assertIn("error", result)
|
|
125
|
-
|
|
126
|
-
async def test_fetch_wallet_balances(self):
|
|
127
|
-
"""Test fetching wallet balances."""
|
|
128
|
-
with patch("skills.moralis.api.fetch_moralis_data") as mock_fetch:
|
|
129
|
-
mock_fetch.return_value = {
|
|
130
|
-
"result": [
|
|
131
|
-
{
|
|
132
|
-
"token_address": "0x123",
|
|
133
|
-
"symbol": "TEST",
|
|
134
|
-
"balance": "1000000",
|
|
135
|
-
"usd_value": 100,
|
|
136
|
-
}
|
|
137
|
-
]
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
result = await fetch_wallet_balances("test_api_key", "0xAddress", 1)
|
|
141
|
-
|
|
142
|
-
self.assertEqual(result["result"][0]["symbol"], "TEST")
|
|
143
|
-
mock_fetch.assert_called_once_with(
|
|
144
|
-
"test_api_key", "wallets/{address}/tokens", "0xAddress", 1, None
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
async def test_get_solana_portfolio(self):
|
|
148
|
-
"""Test getting Solana portfolio."""
|
|
149
|
-
with patch("skills.moralis.api.fetch_solana_api") as mock_fetch:
|
|
150
|
-
mock_fetch.return_value = {
|
|
151
|
-
"nativeBalance": {"solana": 1.5, "lamports": 1500000000},
|
|
152
|
-
"tokens": [
|
|
153
|
-
{
|
|
154
|
-
"symbol": "TEST",
|
|
155
|
-
"name": "Test Token",
|
|
156
|
-
"mint": "TokenMintAddress",
|
|
157
|
-
"associatedTokenAddress": "AssocTokenAddress",
|
|
158
|
-
"amount": 10,
|
|
159
|
-
"decimals": 9,
|
|
160
|
-
"amountRaw": "10000000000",
|
|
161
|
-
}
|
|
162
|
-
],
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
result = await get_solana_portfolio("test_api_key", "SolAddress", "mainnet")
|
|
166
|
-
|
|
167
|
-
mock_fetch.assert_called_once_with(
|
|
168
|
-
"test_api_key", "/account/mainnet/SolAddress/portfolio"
|
|
169
|
-
)
|
|
170
|
-
self.assertEqual(result["nativeBalance"]["solana"], 1.5)
|
|
171
|
-
self.assertEqual(len(result["tokens"]), 1)
|
|
172
|
-
self.assertEqual(result["tokens"][0]["symbol"], "TEST")
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
class TestFetchWalletPortfolio(unittest.IsolatedAsyncioTestCase):
|
|
176
|
-
"""Test the FetchWalletPortfolio skill."""
|
|
177
|
-
|
|
178
|
-
async def test_wallet_portfolio_success(self):
|
|
179
|
-
"""Test successful wallet portfolio fetch."""
|
|
180
|
-
mock_skill_store = MagicMock()
|
|
181
|
-
|
|
182
|
-
with (
|
|
183
|
-
patch(
|
|
184
|
-
"skills.moralis.moralis_fetch_wallet_portfolio.fetch_wallet_balances"
|
|
185
|
-
) as mock_balances,
|
|
186
|
-
patch(
|
|
187
|
-
"skills.moralis.moralis_fetch_wallet_portfolio.fetch_net_worth"
|
|
188
|
-
) as mock_net_worth,
|
|
189
|
-
):
|
|
190
|
-
# Mock successful responses
|
|
191
|
-
mock_balances.return_value = {
|
|
192
|
-
"result": [
|
|
193
|
-
{
|
|
194
|
-
"token_address": "0x123",
|
|
195
|
-
"symbol": "TEST",
|
|
196
|
-
"name": "Test Token",
|
|
197
|
-
"balance": "1000000000000000000",
|
|
198
|
-
"balance_formatted": "1.0",
|
|
199
|
-
"usd_value": 100,
|
|
200
|
-
}
|
|
201
|
-
]
|
|
202
|
-
}
|
|
203
|
-
mock_net_worth.return_value = {"result": {"total_networth_usd": 1000}}
|
|
204
|
-
|
|
205
|
-
tool = FetchWalletPortfolio(
|
|
206
|
-
name="fetch_wallet_portfolio",
|
|
207
|
-
description="Test description",
|
|
208
|
-
args_schema=MagicMock(),
|
|
209
|
-
api_key="test_key",
|
|
210
|
-
skill_store=mock_skill_store,
|
|
211
|
-
agent_id="test_agent",
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
result = await tool._arun(address="0xAddress")
|
|
215
|
-
|
|
216
|
-
self.assertEqual(result.address, "0xAddress")
|
|
217
|
-
self.assertEqual(result.total_net_worth, 1000)
|
|
218
|
-
self.assertEqual(len(result.tokens), 1)
|
|
219
|
-
self.assertEqual(result.tokens[0].symbol, "TEST")
|
|
220
|
-
|
|
221
|
-
async def test_wallet_portfolio_with_solana(self):
|
|
222
|
-
"""Test wallet portfolio with Solana support."""
|
|
223
|
-
mock_skill_store = MagicMock()
|
|
224
|
-
|
|
225
|
-
with (
|
|
226
|
-
patch(
|
|
227
|
-
"skills.moralis.moralis_fetch_wallet_portfolio.fetch_wallet_balances"
|
|
228
|
-
) as mock_evm_balances,
|
|
229
|
-
patch(
|
|
230
|
-
"skills.moralis.moralis_fetch_wallet_portfolio.fetch_net_worth"
|
|
231
|
-
) as mock_net_worth,
|
|
232
|
-
patch(
|
|
233
|
-
"skills.moralis.moralis_fetch_wallet_portfolio.get_solana_portfolio"
|
|
234
|
-
) as mock_sol_portfolio,
|
|
235
|
-
patch(
|
|
236
|
-
"skills.moralis.moralis_fetch_wallet_portfolio.get_token_price"
|
|
237
|
-
) as mock_token_price,
|
|
238
|
-
):
|
|
239
|
-
# Mock EVM responses
|
|
240
|
-
mock_evm_balances.return_value = {
|
|
241
|
-
"result": [
|
|
242
|
-
{
|
|
243
|
-
"token_address": "0x123",
|
|
244
|
-
"symbol": "ETH",
|
|
245
|
-
"name": "Ethereum",
|
|
246
|
-
"balance": "1000000000000000000",
|
|
247
|
-
"balance_formatted": "1.0",
|
|
248
|
-
"usd_value": 2000,
|
|
249
|
-
}
|
|
250
|
-
]
|
|
251
|
-
}
|
|
252
|
-
mock_net_worth.return_value = {"result": {"total_networth_usd": 3000}}
|
|
253
|
-
|
|
254
|
-
# Mock Solana responses
|
|
255
|
-
mock_sol_portfolio.return_value = {
|
|
256
|
-
"nativeBalance": {"solana": 2.0, "lamports": 2000000000},
|
|
257
|
-
"tokens": [
|
|
258
|
-
{
|
|
259
|
-
"symbol": "SOL",
|
|
260
|
-
"name": "Solana",
|
|
261
|
-
"mint": "So11111111111111111111111111111111111111112",
|
|
262
|
-
"associatedTokenAddress": "AssocTokenAddress",
|
|
263
|
-
"amount": 2.0,
|
|
264
|
-
"decimals": 9,
|
|
265
|
-
"amountRaw": "2000000000",
|
|
266
|
-
}
|
|
267
|
-
],
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
mock_token_price.return_value = {"usdPrice": 500}
|
|
271
|
-
|
|
272
|
-
tool = FetchWalletPortfolio(
|
|
273
|
-
name="fetch_wallet_portfolio",
|
|
274
|
-
description="Test description",
|
|
275
|
-
args_schema=MagicMock(),
|
|
276
|
-
api_key="test_key",
|
|
277
|
-
skill_store=mock_skill_store,
|
|
278
|
-
agent_id="test_agent",
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
result = await tool._arun(address="0xAddress", include_solana=True)
|
|
282
|
-
|
|
283
|
-
self.assertEqual(result.address, "0xAddress")
|
|
284
|
-
self.assertEqual(
|
|
285
|
-
result.total_net_worth, 3000
|
|
286
|
-
) # Using the net worth from mock
|
|
287
|
-
self.assertIn("eth", result.chains)
|
|
288
|
-
self.assertIn("solana", result.chains)
|
|
289
|
-
|
|
290
|
-
# Check that we have both EVM and Solana tokens
|
|
291
|
-
token_symbols = [token.symbol for token in result.tokens]
|
|
292
|
-
self.assertIn("ETH", token_symbols)
|
|
293
|
-
self.assertIn("SOL", token_symbols)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
class TestFetchSolanaPortfolio(unittest.IsolatedAsyncioTestCase):
|
|
297
|
-
"""Test the FetchSolanaPortfolio skill."""
|
|
298
|
-
|
|
299
|
-
async def test_solana_portfolio_success(self):
|
|
300
|
-
"""Test successful Solana portfolio fetch."""
|
|
301
|
-
mock_skill_store = MagicMock()
|
|
302
|
-
|
|
303
|
-
with (
|
|
304
|
-
patch(
|
|
305
|
-
"skills.moralis.moralis_fetch_solana_portfolio.get_solana_portfolio"
|
|
306
|
-
) as mock_portfolio,
|
|
307
|
-
patch(
|
|
308
|
-
"skills.moralis.moralis_fetch_solana_portfolio.get_solana_nfts"
|
|
309
|
-
) as mock_nfts,
|
|
310
|
-
patch(
|
|
311
|
-
"skills.moralis.moralis_fetch_solana_portfolio.get_token_price"
|
|
312
|
-
) as mock_token_price,
|
|
313
|
-
):
|
|
314
|
-
# Mock successful responses
|
|
315
|
-
mock_portfolio.return_value = {
|
|
316
|
-
"nativeBalance": {"solana": 1.5, "lamports": 1500000000},
|
|
317
|
-
"tokens": [
|
|
318
|
-
{
|
|
319
|
-
"symbol": "TEST",
|
|
320
|
-
"name": "Test Token",
|
|
321
|
-
"mint": "TokenMintAddress",
|
|
322
|
-
"associatedTokenAddress": "AssocTokenAddress",
|
|
323
|
-
"amount": 10,
|
|
324
|
-
"decimals": 9,
|
|
325
|
-
"amountRaw": "10000000000",
|
|
326
|
-
}
|
|
327
|
-
],
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
mock_nfts.return_value = [
|
|
331
|
-
{
|
|
332
|
-
"mint": "NFTMintAddress",
|
|
333
|
-
"name": "Test NFT",
|
|
334
|
-
"symbol": "TNFT",
|
|
335
|
-
"associatedTokenAddress": "AssocTokenAddress",
|
|
336
|
-
"metadata": {"name": "Test NFT", "image": "image.png"},
|
|
337
|
-
}
|
|
338
|
-
]
|
|
339
|
-
|
|
340
|
-
mock_token_price.return_value = {"usdPrice": 25}
|
|
341
|
-
|
|
342
|
-
tool = FetchSolanaPortfolio(
|
|
343
|
-
name="fetch_solana_portfolio",
|
|
344
|
-
description="Test description",
|
|
345
|
-
args_schema=MagicMock(),
|
|
346
|
-
api_key="test_key",
|
|
347
|
-
skill_store=mock_skill_store,
|
|
348
|
-
agent_id="test_agent",
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
result = await tool._arun(address="SolanaAddress", include_nfts=True)
|
|
352
|
-
|
|
353
|
-
self.assertEqual(result.address, "SolanaAddress")
|
|
354
|
-
self.assertEqual(result.sol_balance, 1.5)
|
|
355
|
-
self.assertEqual(len(result.tokens), 1)
|
|
356
|
-
self.assertEqual(result.tokens[0].token_info.symbol, "TEST")
|
|
357
|
-
self.assertEqual(len(result.nfts), 1)
|
|
358
|
-
self.assertEqual(result.nfts[0].name, "Test NFT")
|
|
359
|
-
self.assertEqual(result.sol_price_usd, 25)
|
|
360
|
-
self.assertEqual(result.sol_value_usd, 37.5) # 1.5 SOL * $25
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
class TestFetchChainPortfolio(unittest.IsolatedAsyncioTestCase):
|
|
364
|
-
"""Test the FetchChainPortfolio skill."""
|
|
365
|
-
|
|
366
|
-
async def test_chain_portfolio_success(self):
|
|
367
|
-
"""Test successful chain portfolio fetch."""
|
|
368
|
-
mock_skill_store = MagicMock()
|
|
369
|
-
|
|
370
|
-
with patch(
|
|
371
|
-
"skills.moralis.moralis_fetch_chain_portfolio.fetch_wallet_balances"
|
|
372
|
-
) as mock_balances:
|
|
373
|
-
# Mock successful responses
|
|
374
|
-
mock_balances.return_value = {
|
|
375
|
-
"result": [
|
|
376
|
-
{
|
|
377
|
-
"token_address": "0x123",
|
|
378
|
-
"symbol": "ETH",
|
|
379
|
-
"name": "Ethereum",
|
|
380
|
-
"logo": "logo.png",
|
|
381
|
-
"decimals": 18,
|
|
382
|
-
"balance": "1000000000000000000",
|
|
383
|
-
"balance_formatted": "1.0",
|
|
384
|
-
"usd_value": 2000,
|
|
385
|
-
"native_token": True,
|
|
386
|
-
},
|
|
387
|
-
{
|
|
388
|
-
"token_address": "0x456",
|
|
389
|
-
"symbol": "TOKEN",
|
|
390
|
-
"name": "Test Token",
|
|
391
|
-
"logo": "logo2.png",
|
|
392
|
-
"decimals": 18,
|
|
393
|
-
"balance": "2000000000000000000",
|
|
394
|
-
"balance_formatted": "2.0",
|
|
395
|
-
"usd_value": 200,
|
|
396
|
-
"native_token": False,
|
|
397
|
-
},
|
|
398
|
-
]
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
tool = FetchChainPortfolio(
|
|
402
|
-
name="fetch_chain_portfolio",
|
|
403
|
-
description="Test description",
|
|
404
|
-
args_schema=MagicMock(),
|
|
405
|
-
api_key="test_key",
|
|
406
|
-
skill_store=mock_skill_store,
|
|
407
|
-
agent_id="test_agent",
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
result = await tool._arun(address="0xAddress", chain_id=1)
|
|
411
|
-
|
|
412
|
-
self.assertEqual(result.address, "0xAddress")
|
|
413
|
-
self.assertEqual(result.chain_id, 1)
|
|
414
|
-
self.assertEqual(result.chain_name, "eth")
|
|
415
|
-
self.assertEqual(result.total_usd_value, 2200) # 2000 + 200
|
|
416
|
-
self.assertEqual(len(result.tokens), 1) # Regular tokens, not native
|
|
417
|
-
self.assertIsNotNone(result.native_token)
|
|
418
|
-
self.assertEqual(result.native_token.symbol, "ETH")
|
|
419
|
-
self.assertEqual(result.tokens[0].symbol, "TOKEN")
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
class TestSkillInitialization(unittest.TestCase):
|
|
423
|
-
"""Test skill initialization and configuration."""
|
|
424
|
-
|
|
425
|
-
def setUp(self):
|
|
426
|
-
self.mock_skill_store = MagicMock()
|
|
427
|
-
|
|
428
|
-
def test_get_skills(self):
|
|
429
|
-
"""Test getting multiple skills from config."""
|
|
430
|
-
config = {
|
|
431
|
-
"api_key": "test_api_key",
|
|
432
|
-
"states": {
|
|
433
|
-
"fetch_wallet_portfolio": "public",
|
|
434
|
-
"fetch_chain_portfolio": "public",
|
|
435
|
-
"fetch_nft_portfolio": "private",
|
|
436
|
-
"fetch_transaction_history": "private",
|
|
437
|
-
"fetch_solana_portfolio": "public",
|
|
438
|
-
},
|
|
439
|
-
"supported_chains": {"evm": True, "solana": True},
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
# Test with mock implementation
|
|
443
|
-
with patch("skills.moralis.base.WalletBaseTool") as mock_tool:
|
|
444
|
-
mock_tool.return_value = MagicMock()
|
|
445
|
-
|
|
446
|
-
# This is just a test structure - actual implementation would create the skills
|
|
447
|
-
skills = get_skills(
|
|
448
|
-
config,
|
|
449
|
-
is_private=False, # Only get public skills
|
|
450
|
-
skill_store=self.mock_skill_store,
|
|
451
|
-
agent_id="test_agent",
|
|
452
|
-
)
|
|
453
|
-
|
|
454
|
-
# In a real implementation, we'd test that the correct skills were returned
|
|
455
|
-
# For now, we just verify the function exists
|
|
456
|
-
self.assertIsNotNone(skills)
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
class TestIntegration(unittest.TestCase):
|
|
460
|
-
"""Integration tests for wallet skills."""
|
|
461
|
-
|
|
462
|
-
def test_wallet_skill_configuration(self):
|
|
463
|
-
"""Test wallet skill configuration in agent config."""
|
|
464
|
-
# Example agent configuration
|
|
465
|
-
agent_config = {
|
|
466
|
-
"id": "crypto-agent",
|
|
467
|
-
"skills": {
|
|
468
|
-
"moralis": {
|
|
469
|
-
"api_key": "test_api_key",
|
|
470
|
-
"states": {
|
|
471
|
-
"fetch_wallet_portfolio": "public",
|
|
472
|
-
"fetch_chain_portfolio": "public",
|
|
473
|
-
"fetch_nft_portfolio": "private",
|
|
474
|
-
"fetch_transaction_history": "private",
|
|
475
|
-
"fetch_solana_portfolio": "public",
|
|
476
|
-
},
|
|
477
|
-
"supported_chains": {"evm": True, "solana": True},
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
# Verify the configuration structure is valid
|
|
483
|
-
moralis_config = agent_config["skills"]["moralis"]
|
|
484
|
-
self.assertIn("api_key", moralis_config)
|
|
485
|
-
self.assertIn("states", moralis_config)
|
|
486
|
-
self.assertIn("supported_chains", moralis_config)
|
|
487
|
-
|
|
488
|
-
# Check that all required skills are configured
|
|
489
|
-
states = moralis_config["states"]
|
|
490
|
-
required_skills = [
|
|
491
|
-
"fetch_wallet_portfolio",
|
|
492
|
-
"fetch_chain_portfolio",
|
|
493
|
-
"fetch_nft_portfolio",
|
|
494
|
-
"fetch_transaction_history",
|
|
495
|
-
"fetch_solana_portfolio",
|
|
496
|
-
]
|
|
497
|
-
|
|
498
|
-
for skill in required_skills:
|
|
499
|
-
self.assertIn(skill, states)
|
|
500
|
-
self.assertIn(states[skill], ["public", "private", "disabled"])
|
|
501
|
-
|
|
502
|
-
# Check chain configuration
|
|
503
|
-
chains = moralis_config["supported_chains"]
|
|
504
|
-
self.assertIn("evm", chains)
|
|
505
|
-
self.assertIn("solana", chains)
|
|
506
|
-
self.assertTrue(isinstance(chains["evm"], bool))
|
|
507
|
-
self.assertTrue(isinstance(chains["solana"], bool))
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
if __name__ == "__main__":
|
|
511
|
-
unittest.main()
|