intentkit 0.5.0__py3-none-any.whl → 0.5.2__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 +17 -0
- intentkit/abstracts/__init__.py +0 -0
- intentkit/abstracts/agent.py +60 -0
- intentkit/abstracts/api.py +4 -0
- intentkit/abstracts/engine.py +38 -0
- intentkit/abstracts/exception.py +9 -0
- intentkit/abstracts/graph.py +25 -0
- intentkit/abstracts/skill.py +129 -0
- intentkit/abstracts/twitter.py +54 -0
- intentkit/clients/__init__.py +14 -0
- intentkit/clients/cdp.py +53 -0
- intentkit/clients/twitter.py +445 -0
- intentkit/config/__init__.py +0 -0
- intentkit/config/config.py +164 -0
- intentkit/core/__init__.py +0 -0
- intentkit/core/agent.py +191 -0
- intentkit/core/api.py +40 -0
- intentkit/core/client.py +45 -0
- intentkit/core/credit.py +1767 -0
- intentkit/core/engine.py +1018 -0
- intentkit/core/node.py +223 -0
- intentkit/core/prompt.py +58 -0
- intentkit/core/skill.py +124 -0
- intentkit/models/agent.py +1689 -0
- intentkit/models/agent_data.py +810 -0
- intentkit/models/agent_schema.json +733 -0
- intentkit/models/app_setting.py +156 -0
- intentkit/models/base.py +9 -0
- intentkit/models/chat.py +581 -0
- intentkit/models/conversation.py +286 -0
- intentkit/models/credit.py +1406 -0
- intentkit/models/db.py +120 -0
- intentkit/models/db_mig.py +102 -0
- intentkit/models/generator.py +347 -0
- intentkit/models/llm.py +746 -0
- intentkit/models/redis.py +132 -0
- intentkit/models/skill.py +466 -0
- intentkit/models/user.py +243 -0
- intentkit/skills/__init__.py +12 -0
- intentkit/skills/acolyt/__init__.py +83 -0
- intentkit/skills/acolyt/acolyt.jpg +0 -0
- intentkit/skills/acolyt/ask.py +128 -0
- intentkit/skills/acolyt/base.py +28 -0
- intentkit/skills/acolyt/schema.json +89 -0
- intentkit/skills/aixbt/README.md +71 -0
- intentkit/skills/aixbt/__init__.py +73 -0
- intentkit/skills/aixbt/aixbt.jpg +0 -0
- intentkit/skills/aixbt/base.py +21 -0
- intentkit/skills/aixbt/projects.py +153 -0
- intentkit/skills/aixbt/schema.json +99 -0
- intentkit/skills/allora/__init__.py +83 -0
- intentkit/skills/allora/allora.jpeg +0 -0
- intentkit/skills/allora/base.py +28 -0
- intentkit/skills/allora/price.py +130 -0
- intentkit/skills/allora/schema.json +89 -0
- intentkit/skills/base.py +174 -0
- intentkit/skills/carv/README.md +95 -0
- intentkit/skills/carv/__init__.py +121 -0
- intentkit/skills/carv/base.py +183 -0
- intentkit/skills/carv/carv.webp +0 -0
- intentkit/skills/carv/fetch_news.py +92 -0
- intentkit/skills/carv/onchain_query.py +164 -0
- intentkit/skills/carv/schema.json +137 -0
- intentkit/skills/carv/token_info_and_price.py +110 -0
- intentkit/skills/cdp/__init__.py +137 -0
- intentkit/skills/cdp/base.py +21 -0
- intentkit/skills/cdp/cdp.png +0 -0
- intentkit/skills/cdp/get_balance.py +81 -0
- intentkit/skills/cdp/schema.json +473 -0
- intentkit/skills/chainlist/README.md +38 -0
- intentkit/skills/chainlist/__init__.py +54 -0
- intentkit/skills/chainlist/base.py +21 -0
- intentkit/skills/chainlist/chain_lookup.py +208 -0
- intentkit/skills/chainlist/chainlist.png +0 -0
- intentkit/skills/chainlist/schema.json +47 -0
- intentkit/skills/common/__init__.py +82 -0
- intentkit/skills/common/base.py +21 -0
- intentkit/skills/common/common.jpg +0 -0
- intentkit/skills/common/current_time.py +84 -0
- intentkit/skills/common/schema.json +57 -0
- intentkit/skills/cookiefun/README.md +121 -0
- intentkit/skills/cookiefun/__init__.py +78 -0
- intentkit/skills/cookiefun/base.py +41 -0
- intentkit/skills/cookiefun/constants.py +18 -0
- intentkit/skills/cookiefun/cookiefun.png +0 -0
- intentkit/skills/cookiefun/get_account_details.py +171 -0
- intentkit/skills/cookiefun/get_account_feed.py +282 -0
- intentkit/skills/cookiefun/get_account_smart_followers.py +181 -0
- intentkit/skills/cookiefun/get_sectors.py +128 -0
- intentkit/skills/cookiefun/schema.json +155 -0
- intentkit/skills/cookiefun/search_accounts.py +225 -0
- intentkit/skills/cryptocompare/__init__.py +130 -0
- intentkit/skills/cryptocompare/api.py +159 -0
- intentkit/skills/cryptocompare/base.py +303 -0
- intentkit/skills/cryptocompare/cryptocompare.png +0 -0
- intentkit/skills/cryptocompare/fetch_news.py +96 -0
- intentkit/skills/cryptocompare/fetch_price.py +99 -0
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +113 -0
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +109 -0
- intentkit/skills/cryptocompare/fetch_top_volume.py +108 -0
- intentkit/skills/cryptocompare/fetch_trading_signals.py +107 -0
- intentkit/skills/cryptocompare/schema.json +168 -0
- intentkit/skills/cryptopanic/__init__.py +108 -0
- intentkit/skills/cryptopanic/base.py +51 -0
- intentkit/skills/cryptopanic/cryptopanic.png +0 -0
- intentkit/skills/cryptopanic/fetch_crypto_news.py +153 -0
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
- intentkit/skills/cryptopanic/schema.json +103 -0
- intentkit/skills/dapplooker/README.md +92 -0
- intentkit/skills/dapplooker/__init__.py +83 -0
- intentkit/skills/dapplooker/base.py +26 -0
- intentkit/skills/dapplooker/dapplooker.jpg +0 -0
- intentkit/skills/dapplooker/dapplooker_token_data.py +476 -0
- intentkit/skills/dapplooker/schema.json +91 -0
- intentkit/skills/defillama/__init__.py +323 -0
- intentkit/skills/defillama/api.py +315 -0
- intentkit/skills/defillama/base.py +135 -0
- intentkit/skills/defillama/coins/__init__.py +0 -0
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
- intentkit/skills/defillama/coins/fetch_block.py +98 -0
- intentkit/skills/defillama/coins/fetch_current_prices.py +105 -0
- intentkit/skills/defillama/coins/fetch_first_price.py +100 -0
- intentkit/skills/defillama/coins/fetch_historical_prices.py +110 -0
- intentkit/skills/defillama/coins/fetch_price_chart.py +109 -0
- intentkit/skills/defillama/coins/fetch_price_percentage.py +93 -0
- intentkit/skills/defillama/config/__init__.py +0 -0
- intentkit/skills/defillama/config/chains.py +433 -0
- intentkit/skills/defillama/defillama.jpeg +0 -0
- intentkit/skills/defillama/fees/__init__.py +0 -0
- intentkit/skills/defillama/fees/fetch_fees_overview.py +130 -0
- intentkit/skills/defillama/schema.json +383 -0
- intentkit/skills/defillama/stablecoins/__init__.py +0 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
- intentkit/skills/defillama/tests/__init__.py +0 -0
- intentkit/skills/defillama/tests/api_integration.test.py +192 -0
- intentkit/skills/defillama/tests/api_unit.test.py +583 -0
- intentkit/skills/defillama/tvl/__init__.py +0 -0
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
- intentkit/skills/defillama/tvl/fetch_chains.py +107 -0
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +91 -0
- intentkit/skills/defillama/tvl/fetch_protocol.py +207 -0
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
- intentkit/skills/defillama/tvl/fetch_protocols.py +196 -0
- intentkit/skills/defillama/volumes/__init__.py +0 -0
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +157 -0
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +123 -0
- intentkit/skills/defillama/volumes/fetch_options_overview.py +131 -0
- intentkit/skills/defillama/yields/__init__.py +0 -0
- intentkit/skills/defillama/yields/fetch_pool_chart.py +100 -0
- intentkit/skills/defillama/yields/fetch_pools.py +126 -0
- intentkit/skills/dexscreener/__init__.py +93 -0
- intentkit/skills/dexscreener/base.py +133 -0
- intentkit/skills/dexscreener/dexscreener.png +0 -0
- intentkit/skills/dexscreener/model/__init__.py +0 -0
- intentkit/skills/dexscreener/model/search_token_response.py +82 -0
- intentkit/skills/dexscreener/schema.json +48 -0
- intentkit/skills/dexscreener/search_token.py +321 -0
- intentkit/skills/dune_analytics/__init__.py +103 -0
- intentkit/skills/dune_analytics/base.py +46 -0
- intentkit/skills/dune_analytics/dune.png +0 -0
- intentkit/skills/dune_analytics/fetch_kol_buys.py +128 -0
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +237 -0
- intentkit/skills/dune_analytics/schema.json +99 -0
- intentkit/skills/elfa/README.md +100 -0
- intentkit/skills/elfa/__init__.py +123 -0
- intentkit/skills/elfa/base.py +28 -0
- intentkit/skills/elfa/elfa.jpg +0 -0
- intentkit/skills/elfa/mention.py +504 -0
- intentkit/skills/elfa/schema.json +153 -0
- intentkit/skills/elfa/stats.py +118 -0
- intentkit/skills/elfa/tokens.py +126 -0
- intentkit/skills/enso/README.md +75 -0
- intentkit/skills/enso/__init__.py +114 -0
- intentkit/skills/enso/abi/__init__.py +0 -0
- intentkit/skills/enso/abi/approval.py +279 -0
- intentkit/skills/enso/abi/erc20.py +14 -0
- intentkit/skills/enso/abi/route.py +129 -0
- intentkit/skills/enso/base.py +44 -0
- intentkit/skills/enso/best_yield.py +286 -0
- intentkit/skills/enso/enso.jpg +0 -0
- intentkit/skills/enso/networks.py +105 -0
- intentkit/skills/enso/prices.py +93 -0
- intentkit/skills/enso/route.py +300 -0
- intentkit/skills/enso/schema.json +212 -0
- intentkit/skills/enso/tokens.py +223 -0
- intentkit/skills/enso/wallet.py +381 -0
- intentkit/skills/github/README.md +63 -0
- intentkit/skills/github/__init__.py +54 -0
- intentkit/skills/github/base.py +21 -0
- intentkit/skills/github/github.jpg +0 -0
- intentkit/skills/github/github_search.py +183 -0
- intentkit/skills/github/schema.json +59 -0
- intentkit/skills/heurist/__init__.py +143 -0
- intentkit/skills/heurist/base.py +26 -0
- intentkit/skills/heurist/heurist.png +0 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_comics.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_real.py +162 -0
- intentkit/skills/heurist/image_generation_braindance.py +162 -0
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
- intentkit/skills/heurist/image_generation_flux_1_dev.py +162 -0
- intentkit/skills/heurist/image_generation_sdxl.py +161 -0
- intentkit/skills/heurist/schema.json +196 -0
- intentkit/skills/lifi/README.md +294 -0
- intentkit/skills/lifi/__init__.py +141 -0
- intentkit/skills/lifi/base.py +21 -0
- intentkit/skills/lifi/lifi.png +0 -0
- intentkit/skills/lifi/schema.json +89 -0
- intentkit/skills/lifi/token_execute.py +472 -0
- intentkit/skills/lifi/token_quote.py +190 -0
- intentkit/skills/lifi/utils.py +656 -0
- intentkit/skills/moralis/README.md +490 -0
- intentkit/skills/moralis/__init__.py +110 -0
- intentkit/skills/moralis/api.py +281 -0
- intentkit/skills/moralis/base.py +55 -0
- intentkit/skills/moralis/fetch_chain_portfolio.py +191 -0
- intentkit/skills/moralis/fetch_nft_portfolio.py +284 -0
- intentkit/skills/moralis/fetch_solana_portfolio.py +331 -0
- intentkit/skills/moralis/fetch_wallet_portfolio.py +301 -0
- intentkit/skills/moralis/moralis.png +0 -0
- intentkit/skills/moralis/schema.json +156 -0
- intentkit/skills/moralis/tests/__init__.py +0 -0
- intentkit/skills/moralis/tests/test_wallet.py +511 -0
- intentkit/skills/nation/__init__.py +62 -0
- intentkit/skills/nation/base.py +31 -0
- intentkit/skills/nation/nation.png +0 -0
- intentkit/skills/nation/nft_check.py +106 -0
- intentkit/skills/nation/schema.json +58 -0
- intentkit/skills/openai/__init__.py +107 -0
- intentkit/skills/openai/base.py +32 -0
- intentkit/skills/openai/dalle_image_generation.py +128 -0
- intentkit/skills/openai/gpt_image_generation.py +152 -0
- intentkit/skills/openai/gpt_image_to_image.py +186 -0
- intentkit/skills/openai/image_to_text.py +126 -0
- intentkit/skills/openai/openai.png +0 -0
- intentkit/skills/openai/schema.json +139 -0
- intentkit/skills/portfolio/README.md +55 -0
- intentkit/skills/portfolio/__init__.py +151 -0
- intentkit/skills/portfolio/base.py +107 -0
- intentkit/skills/portfolio/constants.py +9 -0
- intentkit/skills/portfolio/moralis.png +0 -0
- intentkit/skills/portfolio/schema.json +237 -0
- intentkit/skills/portfolio/token_balances.py +155 -0
- intentkit/skills/portfolio/wallet_approvals.py +102 -0
- intentkit/skills/portfolio/wallet_defi_positions.py +80 -0
- intentkit/skills/portfolio/wallet_history.py +155 -0
- intentkit/skills/portfolio/wallet_net_worth.py +112 -0
- intentkit/skills/portfolio/wallet_nfts.py +139 -0
- intentkit/skills/portfolio/wallet_profitability.py +101 -0
- intentkit/skills/portfolio/wallet_profitability_summary.py +91 -0
- intentkit/skills/portfolio/wallet_stats.py +79 -0
- intentkit/skills/portfolio/wallet_swaps.py +147 -0
- intentkit/skills/skills.toml +103 -0
- intentkit/skills/slack/__init__.py +98 -0
- intentkit/skills/slack/base.py +55 -0
- intentkit/skills/slack/get_channel.py +109 -0
- intentkit/skills/slack/get_message.py +136 -0
- intentkit/skills/slack/schedule_message.py +92 -0
- intentkit/skills/slack/schema.json +135 -0
- intentkit/skills/slack/send_message.py +81 -0
- intentkit/skills/slack/slack.jpg +0 -0
- intentkit/skills/system/__init__.py +90 -0
- intentkit/skills/system/base.py +22 -0
- intentkit/skills/system/read_agent_api_key.py +87 -0
- intentkit/skills/system/regenerate_agent_api_key.py +77 -0
- intentkit/skills/system/schema.json +53 -0
- intentkit/skills/system/system.svg +76 -0
- intentkit/skills/tavily/README.md +86 -0
- intentkit/skills/tavily/__init__.py +91 -0
- intentkit/skills/tavily/base.py +27 -0
- intentkit/skills/tavily/schema.json +119 -0
- intentkit/skills/tavily/tavily.jpg +0 -0
- intentkit/skills/tavily/tavily_extract.py +147 -0
- intentkit/skills/tavily/tavily_search.py +139 -0
- intentkit/skills/token/README.md +89 -0
- intentkit/skills/token/__init__.py +107 -0
- intentkit/skills/token/base.py +154 -0
- intentkit/skills/token/constants.py +9 -0
- intentkit/skills/token/erc20_transfers.py +145 -0
- intentkit/skills/token/moralis.png +0 -0
- intentkit/skills/token/schema.json +141 -0
- intentkit/skills/token/token_analytics.py +81 -0
- intentkit/skills/token/token_price.py +132 -0
- intentkit/skills/token/token_search.py +121 -0
- intentkit/skills/twitter/__init__.py +146 -0
- intentkit/skills/twitter/base.py +68 -0
- intentkit/skills/twitter/follow_user.py +69 -0
- intentkit/skills/twitter/get_mentions.py +124 -0
- intentkit/skills/twitter/get_timeline.py +111 -0
- intentkit/skills/twitter/get_user_by_username.py +84 -0
- intentkit/skills/twitter/get_user_tweets.py +123 -0
- intentkit/skills/twitter/like_tweet.py +65 -0
- intentkit/skills/twitter/post_tweet.py +90 -0
- intentkit/skills/twitter/reply_tweet.py +98 -0
- intentkit/skills/twitter/retweet.py +76 -0
- intentkit/skills/twitter/schema.json +258 -0
- intentkit/skills/twitter/search_tweets.py +115 -0
- intentkit/skills/twitter/twitter.png +0 -0
- intentkit/skills/unrealspeech/__init__.py +55 -0
- intentkit/skills/unrealspeech/base.py +21 -0
- intentkit/skills/unrealspeech/schema.json +100 -0
- intentkit/skills/unrealspeech/text_to_speech.py +177 -0
- intentkit/skills/unrealspeech/unrealspeech.jpg +0 -0
- intentkit/skills/venice_audio/__init__.py +106 -0
- intentkit/skills/venice_audio/base.py +119 -0
- intentkit/skills/venice_audio/input.py +41 -0
- intentkit/skills/venice_audio/schema.json +152 -0
- intentkit/skills/venice_audio/venice_audio.py +240 -0
- intentkit/skills/venice_audio/venice_logo.jpg +0 -0
- intentkit/skills/venice_image/README.md +119 -0
- intentkit/skills/venice_image/__init__.py +154 -0
- intentkit/skills/venice_image/api.py +138 -0
- intentkit/skills/venice_image/base.py +188 -0
- intentkit/skills/venice_image/config.py +35 -0
- intentkit/skills/venice_image/image_enhance/README.md +119 -0
- intentkit/skills/venice_image/image_enhance/__init__.py +0 -0
- intentkit/skills/venice_image/image_enhance/image_enhance.py +80 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_base.py +23 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_input.py +40 -0
- intentkit/skills/venice_image/image_generation/README.md +144 -0
- intentkit/skills/venice_image/image_generation/__init__.py +0 -0
- intentkit/skills/venice_image/image_generation/image_generation_base.py +117 -0
- intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -0
- intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
- intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
- intentkit/skills/venice_image/image_upscale/README.md +111 -0
- intentkit/skills/venice_image/image_upscale/__init__.py +0 -0
- intentkit/skills/venice_image/image_upscale/image_upscale.py +90 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_base.py +23 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -0
- intentkit/skills/venice_image/image_vision/README.md +112 -0
- intentkit/skills/venice_image/image_vision/__init__.py +0 -0
- intentkit/skills/venice_image/image_vision/image_vision.py +100 -0
- intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -0
- intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -0
- intentkit/skills/venice_image/schema.json +267 -0
- intentkit/skills/venice_image/utils.py +78 -0
- intentkit/skills/venice_image/venice_image.jpg +0 -0
- intentkit/skills/web_scraper/README.md +82 -0
- intentkit/skills/web_scraper/__init__.py +92 -0
- intentkit/skills/web_scraper/base.py +21 -0
- intentkit/skills/web_scraper/langchain.png +0 -0
- intentkit/skills/web_scraper/schema.json +115 -0
- intentkit/skills/web_scraper/scrape_and_index.py +327 -0
- intentkit/utils/__init__.py +1 -0
- intentkit/utils/chain.py +436 -0
- intentkit/utils/error.py +134 -0
- intentkit/utils/logging.py +70 -0
- intentkit/utils/middleware.py +61 -0
- intentkit/utils/random.py +16 -0
- intentkit/utils/s3.py +267 -0
- intentkit/utils/slack_alert.py +79 -0
- intentkit/utils/tx.py +37 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/METADATA +1 -1
- intentkit-0.5.2.dist-info/RECORD +365 -0
- intentkit-0.5.0.dist-info/RECORD +0 -4
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/WHEEL +0 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Tool for fetching stablecoin charts via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional, Type
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_stablecoin_charts
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_STABLECOIN_CHARTS_PROMPT = """
|
|
12
|
+
This tool fetches historical circulating supply data from DeFi Llama for a specific stablecoin.
|
|
13
|
+
Required:
|
|
14
|
+
- Stablecoin ID
|
|
15
|
+
Optional:
|
|
16
|
+
- Chain name for chain-specific data
|
|
17
|
+
Returns historical data including:
|
|
18
|
+
- Total circulating supply
|
|
19
|
+
- Circulating supply in USD
|
|
20
|
+
- Daily data points
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CirculatingSupply(BaseModel):
|
|
25
|
+
"""Model representing circulating supply amounts."""
|
|
26
|
+
|
|
27
|
+
peggedUSD: float = Field(..., description="Amount pegged to USD")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class StablecoinDataPoint(BaseModel):
|
|
31
|
+
"""Model representing a single historical data point."""
|
|
32
|
+
|
|
33
|
+
date: str = Field(..., description="Unix timestamp of the data point")
|
|
34
|
+
totalCirculating: CirculatingSupply = Field(
|
|
35
|
+
..., description="Total circulating supply"
|
|
36
|
+
)
|
|
37
|
+
totalCirculatingUSD: CirculatingSupply = Field(
|
|
38
|
+
..., description="Total circulating supply in USD"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class FetchStablecoinChartsInput(BaseModel):
|
|
43
|
+
"""Input schema for fetching stablecoin chart data."""
|
|
44
|
+
|
|
45
|
+
stablecoin_id: str = Field(
|
|
46
|
+
..., description="ID of the stablecoin to fetch data for"
|
|
47
|
+
)
|
|
48
|
+
chain: Optional[str] = Field(
|
|
49
|
+
None, description="Optional chain name for chain-specific data"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class FetchStablecoinChartsResponse(BaseModel):
|
|
54
|
+
"""Response schema for stablecoin chart data."""
|
|
55
|
+
|
|
56
|
+
data: List[StablecoinDataPoint] = Field(
|
|
57
|
+
default_factory=list, description="List of historical data points"
|
|
58
|
+
)
|
|
59
|
+
chain: Optional[str] = Field(
|
|
60
|
+
None, description="Chain name if chain-specific data was requested"
|
|
61
|
+
)
|
|
62
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class DefiLlamaFetchStablecoinCharts(DefiLlamaBaseTool):
|
|
66
|
+
"""Tool for fetching stablecoin chart data from DeFi Llama.
|
|
67
|
+
|
|
68
|
+
This tool retrieves historical circulating supply data for a specific stablecoin,
|
|
69
|
+
optionally filtered by chain.
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
charts_tool = DefiLlamaFetchStablecoinCharts(
|
|
73
|
+
skill_store=store,
|
|
74
|
+
agent_id="agent_123",
|
|
75
|
+
agent_store=agent_store
|
|
76
|
+
)
|
|
77
|
+
# Get all chains data
|
|
78
|
+
result = await charts_tool._arun(stablecoin_id="1")
|
|
79
|
+
# Get chain-specific data
|
|
80
|
+
result = await charts_tool._arun(stablecoin_id="1", chain="ethereum")
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
name: str = "defillama_fetch_stablecoin_charts"
|
|
84
|
+
description: str = FETCH_STABLECOIN_CHARTS_PROMPT
|
|
85
|
+
args_schema: Type[BaseModel] = FetchStablecoinChartsInput
|
|
86
|
+
|
|
87
|
+
async def _arun(
|
|
88
|
+
self, config: RunnableConfig, stablecoin_id: str, chain: Optional[str] = None
|
|
89
|
+
) -> FetchStablecoinChartsResponse:
|
|
90
|
+
"""Fetch historical chart data for the given stablecoin.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
config: Runnable configuration
|
|
94
|
+
stablecoin_id: ID of the stablecoin to fetch data for
|
|
95
|
+
chain: Optional chain name for chain-specific data
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
FetchStablecoinChartsResponse containing historical data or error
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
# Validate chain if provided
|
|
102
|
+
if chain:
|
|
103
|
+
is_valid, normalized_chain = await self.validate_chain(chain)
|
|
104
|
+
if not is_valid:
|
|
105
|
+
return FetchStablecoinChartsResponse(
|
|
106
|
+
error=f"Invalid chain: {chain}"
|
|
107
|
+
)
|
|
108
|
+
chain = normalized_chain
|
|
109
|
+
|
|
110
|
+
# Check rate limiting
|
|
111
|
+
context = self.context_from_config(config)
|
|
112
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
113
|
+
if is_rate_limited:
|
|
114
|
+
return FetchStablecoinChartsResponse(error=error_msg)
|
|
115
|
+
|
|
116
|
+
# Fetch chart data from API
|
|
117
|
+
result = await fetch_stablecoin_charts(
|
|
118
|
+
stablecoin_id=stablecoin_id, chain=chain
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Check for API errors
|
|
122
|
+
if isinstance(result, dict) and "error" in result:
|
|
123
|
+
return FetchStablecoinChartsResponse(error=result["error"])
|
|
124
|
+
|
|
125
|
+
# Parse response data
|
|
126
|
+
return FetchStablecoinChartsResponse(data=result, chain=chain)
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return FetchStablecoinChartsResponse(error=str(e))
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Tool for fetching stablecoin prices via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_stablecoin_prices
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_STABLECOIN_PRICES_PROMPT = """
|
|
12
|
+
This tool fetches current price data for stablecoins from DeFi Llama.
|
|
13
|
+
Returns:
|
|
14
|
+
- Historical price points with timestamps
|
|
15
|
+
- Current prices for each stablecoin
|
|
16
|
+
- Prices indexed by stablecoin identifier
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PriceDataPoint(BaseModel):
|
|
21
|
+
"""Model representing a price data point."""
|
|
22
|
+
|
|
23
|
+
date: str = Field(..., description="Unix timestamp for the price data")
|
|
24
|
+
prices: Dict[str, float] = Field(
|
|
25
|
+
..., description="Dictionary of stablecoin prices indexed by identifier"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FetchStablecoinPricesResponse(BaseModel):
|
|
30
|
+
"""Response schema for stablecoin prices data."""
|
|
31
|
+
|
|
32
|
+
data: List[PriceDataPoint] = Field(
|
|
33
|
+
default_factory=list, description="List of price data points"
|
|
34
|
+
)
|
|
35
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DefiLlamaFetchStablecoinPrices(DefiLlamaBaseTool):
|
|
39
|
+
"""Tool for fetching stablecoin prices from DeFi Llama.
|
|
40
|
+
|
|
41
|
+
This tool retrieves current price data for stablecoins, including historical
|
|
42
|
+
price points and their timestamps.
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
prices_tool = DefiLlamaFetchStablecoinPrices(
|
|
46
|
+
skill_store=store,
|
|
47
|
+
agent_id="agent_123",
|
|
48
|
+
agent_store=agent_store
|
|
49
|
+
)
|
|
50
|
+
result = await prices_tool._arun()
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
name: str = "defillama_fetch_stablecoin_prices"
|
|
54
|
+
description: str = FETCH_STABLECOIN_PRICES_PROMPT
|
|
55
|
+
args_schema: None = None # No input parameters needed
|
|
56
|
+
|
|
57
|
+
async def _arun(self, config: RunnableConfig) -> FetchStablecoinPricesResponse:
|
|
58
|
+
"""Fetch stablecoin price data.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
FetchStablecoinPricesResponse containing price data or error
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
# Check rate limiting
|
|
65
|
+
context = self.context_from_config(config)
|
|
66
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
67
|
+
if is_rate_limited:
|
|
68
|
+
return FetchStablecoinPricesResponse(error=error_msg)
|
|
69
|
+
|
|
70
|
+
# Fetch price data from API
|
|
71
|
+
result = await fetch_stablecoin_prices()
|
|
72
|
+
|
|
73
|
+
# Check for API errors
|
|
74
|
+
if isinstance(result, dict) and "error" in result:
|
|
75
|
+
return FetchStablecoinPricesResponse(error=result["error"])
|
|
76
|
+
|
|
77
|
+
# Parse results into models
|
|
78
|
+
data_points = [PriceDataPoint(**point) for point in result]
|
|
79
|
+
|
|
80
|
+
return FetchStablecoinPricesResponse(data=data_points)
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
return FetchStablecoinPricesResponse(error=str(e))
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Tool for fetching stablecoin data via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_stablecoins
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_STABLECOINS_PROMPT = """
|
|
12
|
+
This tool fetches comprehensive stablecoin data from DeFi Llama.
|
|
13
|
+
Returns:
|
|
14
|
+
- List of stablecoins with details like name, symbol, market cap
|
|
15
|
+
- Per-chain circulating amounts
|
|
16
|
+
- Historical circulating amounts (day/week/month)
|
|
17
|
+
- Current prices and price history
|
|
18
|
+
- Peg mechanism and type information
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CirculatingAmount(BaseModel):
|
|
23
|
+
"""Model representing circulating amounts for a specific peg type."""
|
|
24
|
+
|
|
25
|
+
peggedUSD: float = Field(..., description="Amount pegged to USD")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ChainCirculating(BaseModel):
|
|
29
|
+
"""Model representing circulating amounts on a specific chain."""
|
|
30
|
+
|
|
31
|
+
current: CirculatingAmount = Field(..., description="Current circulating amount")
|
|
32
|
+
circulatingPrevDay: CirculatingAmount = Field(
|
|
33
|
+
..., description="Circulating amount from previous day"
|
|
34
|
+
)
|
|
35
|
+
circulatingPrevWeek: CirculatingAmount = Field(
|
|
36
|
+
..., description="Circulating amount from previous week"
|
|
37
|
+
)
|
|
38
|
+
circulatingPrevMonth: CirculatingAmount = Field(
|
|
39
|
+
..., description="Circulating amount from previous month"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Stablecoin(BaseModel):
|
|
44
|
+
"""Model representing a single stablecoin's data."""
|
|
45
|
+
|
|
46
|
+
id: str = Field(..., description="Unique identifier")
|
|
47
|
+
name: str = Field(..., description="Stablecoin name")
|
|
48
|
+
symbol: str = Field(..., description="Token symbol")
|
|
49
|
+
gecko_id: Optional[str] = Field(None, description="CoinGecko ID if available")
|
|
50
|
+
pegType: str = Field(..., description="Type of peg (e.g. peggedUSD)")
|
|
51
|
+
priceSource: str = Field(..., description="Source of price data")
|
|
52
|
+
pegMechanism: str = Field(..., description="Mechanism maintaining the peg")
|
|
53
|
+
circulating: CirculatingAmount = Field(
|
|
54
|
+
..., description="Current total circulating amount"
|
|
55
|
+
)
|
|
56
|
+
circulatingPrevDay: CirculatingAmount = Field(
|
|
57
|
+
..., description="Total circulating amount from previous day"
|
|
58
|
+
)
|
|
59
|
+
circulatingPrevWeek: CirculatingAmount = Field(
|
|
60
|
+
..., description="Total circulating amount from previous week"
|
|
61
|
+
)
|
|
62
|
+
circulatingPrevMonth: CirculatingAmount = Field(
|
|
63
|
+
..., description="Total circulating amount from previous month"
|
|
64
|
+
)
|
|
65
|
+
chainCirculating: Dict[str, ChainCirculating] = Field(
|
|
66
|
+
..., description="Circulating amounts per chain"
|
|
67
|
+
)
|
|
68
|
+
chains: List[str] = Field(
|
|
69
|
+
..., description="List of chains where the stablecoin is present"
|
|
70
|
+
)
|
|
71
|
+
price: float = Field(..., description="Current price in USD")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class FetchStablecoinsResponse(BaseModel):
|
|
75
|
+
"""Response schema for stablecoin data."""
|
|
76
|
+
|
|
77
|
+
peggedAssets: List[Stablecoin] = Field(
|
|
78
|
+
default_factory=list, description="List of stablecoins with their data"
|
|
79
|
+
)
|
|
80
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class DefiLlamaFetchStablecoins(DefiLlamaBaseTool):
|
|
84
|
+
"""Tool for fetching stablecoin data from DeFi Llama.
|
|
85
|
+
|
|
86
|
+
This tool retrieves comprehensive data about stablecoins, including their
|
|
87
|
+
circulating supply across different chains, price information, and peg details.
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
stablecoins_tool = DefiLlamaFetchStablecoins(
|
|
91
|
+
skill_store=store,
|
|
92
|
+
agent_id="agent_123",
|
|
93
|
+
agent_store=agent_store
|
|
94
|
+
)
|
|
95
|
+
result = await stablecoins_tool._arun()
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
name: str = "defillama_fetch_stablecoins"
|
|
99
|
+
description: str = FETCH_STABLECOINS_PROMPT
|
|
100
|
+
args_schema: None = None # No input parameters needed
|
|
101
|
+
|
|
102
|
+
async def _arun(self, config: RunnableConfig) -> FetchStablecoinsResponse:
|
|
103
|
+
"""Fetch stablecoin data.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
FetchStablecoinsResponse containing stablecoin data or error
|
|
107
|
+
"""
|
|
108
|
+
try:
|
|
109
|
+
# Check rate limiting
|
|
110
|
+
context = self.context_from_config(config)
|
|
111
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
112
|
+
if is_rate_limited:
|
|
113
|
+
return FetchStablecoinsResponse(error=error_msg)
|
|
114
|
+
|
|
115
|
+
# Fetch stablecoin data from API
|
|
116
|
+
result = await fetch_stablecoins()
|
|
117
|
+
|
|
118
|
+
# Check for API errors
|
|
119
|
+
if isinstance(result, dict) and "error" in result:
|
|
120
|
+
return FetchStablecoinsResponse(error=result["error"])
|
|
121
|
+
|
|
122
|
+
# Return the response matching the API structure
|
|
123
|
+
return FetchStablecoinsResponse(**result)
|
|
124
|
+
|
|
125
|
+
except Exception as e:
|
|
126
|
+
return FetchStablecoinsResponse(error=str(e))
|
|
File without changes
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import unittest
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
from unittest.runner import TextTestResult
|
|
6
|
+
|
|
7
|
+
# Import all functions from your API module
|
|
8
|
+
from intentkit.skills.defillama.api import (
|
|
9
|
+
fetch_chains,
|
|
10
|
+
fetch_current_prices,
|
|
11
|
+
fetch_dex_overview,
|
|
12
|
+
fetch_dex_summary,
|
|
13
|
+
fetch_fees_overview,
|
|
14
|
+
fetch_historical_prices,
|
|
15
|
+
fetch_historical_tvl,
|
|
16
|
+
fetch_price_chart,
|
|
17
|
+
fetch_protocol,
|
|
18
|
+
fetch_protocols,
|
|
19
|
+
fetch_stablecoin_chains,
|
|
20
|
+
fetch_stablecoin_prices,
|
|
21
|
+
fetch_stablecoins,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Configure logging to only show warnings and errors
|
|
25
|
+
logging.basicConfig(level=logging.WARNING)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class QuietTestResult(TextTestResult):
|
|
29
|
+
"""Custom TestResult class that minimizes output unless there's a failure"""
|
|
30
|
+
|
|
31
|
+
def startTest(self, test):
|
|
32
|
+
self._started_at = datetime.now()
|
|
33
|
+
super().startTest(test)
|
|
34
|
+
|
|
35
|
+
def addSuccess(self, test):
|
|
36
|
+
super().addSuccess(test)
|
|
37
|
+
if self.showAll:
|
|
38
|
+
self.stream.write("")
|
|
39
|
+
self.stream.flush()
|
|
40
|
+
|
|
41
|
+
def addError(self, test, err):
|
|
42
|
+
super().addError(test, err)
|
|
43
|
+
self.stream.write("\n")
|
|
44
|
+
self.stream.write(self.separator1 + "\n")
|
|
45
|
+
self.stream.write(f"ERROR: {self.getDescription(test)}\n")
|
|
46
|
+
self.stream.write(self.separator2 + "\n")
|
|
47
|
+
self.stream.write(self._exc_info_to_string(err, test))
|
|
48
|
+
self.stream.write("\n")
|
|
49
|
+
self.stream.flush()
|
|
50
|
+
|
|
51
|
+
def addFailure(self, test, err):
|
|
52
|
+
super().addFailure(test, err)
|
|
53
|
+
self.stream.write("\n")
|
|
54
|
+
self.stream.write(self.separator1 + "\n")
|
|
55
|
+
self.stream.write(f"FAIL: {self.getDescription(test)}\n")
|
|
56
|
+
self.stream.write(self.separator2 + "\n")
|
|
57
|
+
self.stream.write(self._exc_info_to_string(err, test))
|
|
58
|
+
self.stream.write("\n")
|
|
59
|
+
self.stream.flush()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class QuietTestRunner(unittest.TextTestRunner):
|
|
63
|
+
"""Custom TestRunner that uses QuietTestResult"""
|
|
64
|
+
|
|
65
|
+
resultclass = QuietTestResult
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestDefiLlamaAPI(unittest.TestCase):
|
|
69
|
+
"""Integration tests for DeFi Llama API client"""
|
|
70
|
+
|
|
71
|
+
def setUp(self):
|
|
72
|
+
"""Set up the async event loop"""
|
|
73
|
+
self.loop = asyncio.new_event_loop()
|
|
74
|
+
asyncio.set_event_loop(self.loop)
|
|
75
|
+
self.timeout = 3000
|
|
76
|
+
|
|
77
|
+
def tearDown(self):
|
|
78
|
+
"""Clean up the event loop"""
|
|
79
|
+
self.loop.close()
|
|
80
|
+
|
|
81
|
+
def run_async(self, coro):
|
|
82
|
+
"""Helper to run async functions in test methods with timeout"""
|
|
83
|
+
try:
|
|
84
|
+
return self.loop.run_until_complete(
|
|
85
|
+
asyncio.wait_for(coro, timeout=self.timeout)
|
|
86
|
+
)
|
|
87
|
+
except asyncio.TimeoutError:
|
|
88
|
+
raise AssertionError(f"Test timed out after {self.timeout} seconds")
|
|
89
|
+
except Exception as e:
|
|
90
|
+
raise AssertionError(f"Test failed with exception: {str(e)}")
|
|
91
|
+
|
|
92
|
+
def assert_successful_response(self, response):
|
|
93
|
+
"""Helper to check if response contains an error"""
|
|
94
|
+
if isinstance(response, dict) and "error" in response:
|
|
95
|
+
raise AssertionError(f"API request failed: {response['error']}")
|
|
96
|
+
|
|
97
|
+
def test_tvl_endpoints(self):
|
|
98
|
+
"""Test TVL-related endpoints"""
|
|
99
|
+
# Test fetch_protocols
|
|
100
|
+
protocols = self.run_async(fetch_protocols())
|
|
101
|
+
self.assert_successful_response(protocols)
|
|
102
|
+
self.assertIsInstance(protocols, list)
|
|
103
|
+
if len(protocols) > 0:
|
|
104
|
+
self.assertIn("tvl", protocols[0])
|
|
105
|
+
|
|
106
|
+
# Test fetch_protocol using Aave as an example
|
|
107
|
+
protocol_data = self.run_async(fetch_protocol("aave"))
|
|
108
|
+
self.assert_successful_response(protocol_data)
|
|
109
|
+
self.assertIsInstance(protocol_data, dict)
|
|
110
|
+
|
|
111
|
+
# Test fetch_historical_tvl
|
|
112
|
+
historical_tvl = self.run_async(fetch_historical_tvl())
|
|
113
|
+
self.assert_successful_response(historical_tvl)
|
|
114
|
+
self.assertIsInstance(historical_tvl, list)
|
|
115
|
+
# Verify the structure of historical TVL data points
|
|
116
|
+
if len(historical_tvl) > 0:
|
|
117
|
+
self.assertIn("date", historical_tvl[0])
|
|
118
|
+
self.assertIn("tvl", historical_tvl[0])
|
|
119
|
+
|
|
120
|
+
# Test fetch_chains
|
|
121
|
+
chains = self.run_async(fetch_chains())
|
|
122
|
+
self.assert_successful_response(chains)
|
|
123
|
+
self.assertIsInstance(chains, list)
|
|
124
|
+
|
|
125
|
+
def test_coins_endpoints(self):
|
|
126
|
+
"""Test coin price-related endpoints"""
|
|
127
|
+
test_coins = ["ethereum:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]
|
|
128
|
+
|
|
129
|
+
# Test fetch_current_prices
|
|
130
|
+
current_prices = self.run_async(fetch_current_prices(test_coins))
|
|
131
|
+
self.assert_successful_response(current_prices)
|
|
132
|
+
self.assertIsInstance(current_prices, dict)
|
|
133
|
+
|
|
134
|
+
# Test fetch_historical_prices
|
|
135
|
+
timestamp = int((datetime.now() - timedelta(days=1)).timestamp())
|
|
136
|
+
historical_prices = self.run_async(
|
|
137
|
+
fetch_historical_prices(timestamp, test_coins)
|
|
138
|
+
)
|
|
139
|
+
self.assert_successful_response(historical_prices)
|
|
140
|
+
self.assertIsInstance(historical_prices, dict)
|
|
141
|
+
|
|
142
|
+
# Test fetch_price_chart
|
|
143
|
+
price_chart = self.run_async(fetch_price_chart(test_coins))
|
|
144
|
+
self.assert_successful_response(price_chart)
|
|
145
|
+
self.assertIsInstance(price_chart, dict)
|
|
146
|
+
self.assertIn("coins", price_chart)
|
|
147
|
+
# Verify the structure of the response
|
|
148
|
+
coin_data = price_chart["coins"].get(test_coins[0])
|
|
149
|
+
self.assertIsNotNone(coin_data)
|
|
150
|
+
self.assertIn("prices", coin_data)
|
|
151
|
+
self.assertIsInstance(coin_data["prices"], list)
|
|
152
|
+
|
|
153
|
+
def test_stablecoin_endpoints(self):
|
|
154
|
+
"""Test stablecoin-related endpoints"""
|
|
155
|
+
# Test fetch_stablecoins
|
|
156
|
+
stablecoins = self.run_async(fetch_stablecoins())
|
|
157
|
+
self.assert_successful_response(stablecoins)
|
|
158
|
+
self.assertIsInstance(stablecoins, dict)
|
|
159
|
+
|
|
160
|
+
# Test fetch_stablecoin_chains
|
|
161
|
+
chains = self.run_async(fetch_stablecoin_chains())
|
|
162
|
+
self.assert_successful_response(chains)
|
|
163
|
+
self.assertIsInstance(chains, list)
|
|
164
|
+
|
|
165
|
+
# Test fetch_stablecoin_prices
|
|
166
|
+
prices = self.run_async(fetch_stablecoin_prices())
|
|
167
|
+
self.assert_successful_response(prices)
|
|
168
|
+
self.assertIsInstance(prices, list)
|
|
169
|
+
|
|
170
|
+
def test_volume_endpoints(self):
|
|
171
|
+
"""Test volume-related endpoints"""
|
|
172
|
+
# Test fetch_dex_overview
|
|
173
|
+
dex_overview = self.run_async(fetch_dex_overview())
|
|
174
|
+
self.assert_successful_response(dex_overview)
|
|
175
|
+
self.assertIsInstance(dex_overview, dict)
|
|
176
|
+
|
|
177
|
+
# Test fetch_dex_summary using Uniswap as example
|
|
178
|
+
dex_summary = self.run_async(fetch_dex_summary("uniswap"))
|
|
179
|
+
self.assert_successful_response(dex_summary)
|
|
180
|
+
self.assertIsInstance(dex_summary, dict)
|
|
181
|
+
|
|
182
|
+
def test_fees_endpoint(self):
|
|
183
|
+
"""Test fees endpoint"""
|
|
184
|
+
fees_overview = self.run_async(fetch_fees_overview())
|
|
185
|
+
self.assert_successful_response(fees_overview)
|
|
186
|
+
self.assertIsInstance(fees_overview, dict)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if __name__ == "__main__":
|
|
190
|
+
# Use the quiet test runner
|
|
191
|
+
runner = QuietTestRunner(verbosity=1)
|
|
192
|
+
unittest.main(testRunner=runner)
|