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,281 @@
|
|
|
1
|
+
"""API interface for wallet data providers (EVM chains and Solana)."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.moralis.base import CHAIN_MAPPING
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
#############################################
|
|
13
|
+
# EVM Chains API (Ethereum, BSC, etc.)
|
|
14
|
+
#############################################
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def fetch_moralis_data(
|
|
18
|
+
api_key: str, endpoint: str, address: str, chain_id: int = None, params: dict = None
|
|
19
|
+
) -> dict:
|
|
20
|
+
"""Base function for Moralis API calls.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
api_key: Moralis API key
|
|
24
|
+
endpoint: API endpoint (with {address} placeholder if needed)
|
|
25
|
+
address: Wallet address to query
|
|
26
|
+
chain_id: Blockchain network ID
|
|
27
|
+
params: Additional query parameters
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Response data from the API or error
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
if not api_key:
|
|
34
|
+
logger.error("API key not configured")
|
|
35
|
+
return {"error": "API key not configured"}
|
|
36
|
+
|
|
37
|
+
base_url = "https://deep-index.moralis.io/api/v2.2"
|
|
38
|
+
headers = {"X-API-Key": api_key}
|
|
39
|
+
|
|
40
|
+
url = f"{base_url}/{endpoint.format(address=address)}"
|
|
41
|
+
|
|
42
|
+
if chain_id:
|
|
43
|
+
params = params or {}
|
|
44
|
+
params["chain"] = CHAIN_MAPPING.get(chain_id, "eth")
|
|
45
|
+
|
|
46
|
+
async with httpx.AsyncClient() as client:
|
|
47
|
+
try:
|
|
48
|
+
response = await client.get(url, headers=headers, params=params)
|
|
49
|
+
response.raise_for_status()
|
|
50
|
+
return response.json()
|
|
51
|
+
except httpx.RequestError as e:
|
|
52
|
+
logger.error(f"API request error: {e}")
|
|
53
|
+
return {"error": str(e)}
|
|
54
|
+
except httpx.HTTPStatusError as e:
|
|
55
|
+
logger.error(f"API error: {e.response.status_code} {e.response.text}")
|
|
56
|
+
return {"error": f"HTTP error {e.response.status_code}"}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Wallet Balances
|
|
60
|
+
async def fetch_wallet_balances(
|
|
61
|
+
api_key: str, address: str, chain_id: int = None
|
|
62
|
+
) -> dict:
|
|
63
|
+
"""Get token balances with prices.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
api_key: API key for the data provider
|
|
67
|
+
address: Wallet address to query
|
|
68
|
+
chain_id: Blockchain network ID
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Token balances with additional data
|
|
72
|
+
"""
|
|
73
|
+
endpoint = "wallets/{address}/tokens"
|
|
74
|
+
return await fetch_moralis_data(api_key, endpoint, address, chain_id)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# NFT Balances
|
|
78
|
+
async def fetch_nft_data(
|
|
79
|
+
api_key: str, address: str, chain_id: int = None, params: dict = None
|
|
80
|
+
) -> dict:
|
|
81
|
+
"""Get NFT balances.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
api_key: API key for the data provider
|
|
85
|
+
address: Wallet address to query
|
|
86
|
+
chain_id: Blockchain network ID
|
|
87
|
+
params: Additional query parameters
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
NFT data including metadata
|
|
91
|
+
"""
|
|
92
|
+
endpoint = "{address}/nft"
|
|
93
|
+
default_params = {"normalizeMetadata": True}
|
|
94
|
+
if params:
|
|
95
|
+
default_params.update(params)
|
|
96
|
+
return await fetch_moralis_data(
|
|
97
|
+
api_key, endpoint, address, chain_id, default_params
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# Transaction History
|
|
102
|
+
async def fetch_transaction_history(
|
|
103
|
+
api_key: str,
|
|
104
|
+
address: str,
|
|
105
|
+
chain_id: int = None,
|
|
106
|
+
cursor: str = None,
|
|
107
|
+
limit: int = 100,
|
|
108
|
+
) -> dict:
|
|
109
|
+
"""Get wallet transaction history.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
api_key: API key for the data provider
|
|
113
|
+
address: Wallet address to query
|
|
114
|
+
chain_id: Blockchain network ID
|
|
115
|
+
cursor: Pagination cursor
|
|
116
|
+
limit: Maximum number of transactions to return
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Transaction history data
|
|
120
|
+
"""
|
|
121
|
+
endpoint = "wallets/{address}/history"
|
|
122
|
+
params = {"limit": limit}
|
|
123
|
+
if cursor:
|
|
124
|
+
params["cursor"] = cursor
|
|
125
|
+
return await fetch_moralis_data(api_key, endpoint, address, chain_id, params)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Token Approvals
|
|
129
|
+
async def fetch_token_approvals(
|
|
130
|
+
api_key: str, address: str, chain_id: int = None
|
|
131
|
+
) -> dict:
|
|
132
|
+
"""Get token approvals.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
api_key: API key for the data provider
|
|
136
|
+
address: Wallet address to query
|
|
137
|
+
chain_id: Blockchain network ID
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Token approval data
|
|
141
|
+
"""
|
|
142
|
+
endpoint = "wallets/{address}/approvals"
|
|
143
|
+
return await fetch_moralis_data(api_key, endpoint, address, chain_id)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# Net Worth
|
|
147
|
+
async def fetch_net_worth(api_key: str, address: str) -> dict:
|
|
148
|
+
"""Get wallet net worth.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
api_key: API key for the data provider
|
|
152
|
+
address: Wallet address to query
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Net worth data across all chains
|
|
156
|
+
"""
|
|
157
|
+
endpoint = "wallets/{address}/net-worth"
|
|
158
|
+
return await fetch_moralis_data(api_key, endpoint, address)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
#############################################
|
|
162
|
+
# Solana API
|
|
163
|
+
#############################################
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
async def fetch_solana_api(api_key: str, endpoint: str, params: Dict = None) -> Dict:
|
|
167
|
+
"""Base function for Solana API calls using Moralis.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
api_key: API key for the data provider
|
|
171
|
+
endpoint: API endpoint
|
|
172
|
+
params: Additional query parameters
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Response data from the API or error
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
if not api_key:
|
|
179
|
+
logger.error("API key not configured")
|
|
180
|
+
return {"error": "API key not configured"}
|
|
181
|
+
|
|
182
|
+
base_url = "https://solana-gateway.moralis.io"
|
|
183
|
+
headers = {"X-API-Key": api_key}
|
|
184
|
+
url = f"{base_url}{endpoint}"
|
|
185
|
+
|
|
186
|
+
async with httpx.AsyncClient() as client:
|
|
187
|
+
try:
|
|
188
|
+
response = await client.get(url, headers=headers, params=params)
|
|
189
|
+
response.raise_for_status()
|
|
190
|
+
return response.json()
|
|
191
|
+
except httpx.RequestError as e:
|
|
192
|
+
logger.error(f"Solana API request error: {e}")
|
|
193
|
+
return {"error": str(e)}
|
|
194
|
+
except httpx.HTTPStatusError as e:
|
|
195
|
+
logger.error(
|
|
196
|
+
f"Solana API error: {e.response.status_code} {e.response.text}"
|
|
197
|
+
)
|
|
198
|
+
return {"error": f"HTTP error {e.response.status_code}: {e.response.text}"}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
async def get_solana_portfolio(
|
|
202
|
+
api_key: str, address: str, network: str = "mainnet"
|
|
203
|
+
) -> Dict:
|
|
204
|
+
"""Get complete portfolio for a Solana wallet.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
api_key: API key for the data provider
|
|
208
|
+
address: Solana wallet address
|
|
209
|
+
network: Solana network (mainnet or devnet)
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Complete portfolio including SOL and SPL tokens
|
|
213
|
+
"""
|
|
214
|
+
endpoint = f"/account/{network}/{address}/portfolio"
|
|
215
|
+
return await fetch_solana_api(api_key, endpoint)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
async def get_solana_balance(
|
|
219
|
+
api_key: str, address: str, network: str = "mainnet"
|
|
220
|
+
) -> Dict:
|
|
221
|
+
"""Get native SOL balance.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
api_key: API key for the data provider
|
|
225
|
+
address: Solana wallet address
|
|
226
|
+
network: Solana network (mainnet or devnet)
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Native SOL balance
|
|
230
|
+
"""
|
|
231
|
+
endpoint = f"/account/{network}/{address}/balance"
|
|
232
|
+
return await fetch_solana_api(api_key, endpoint)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
async def get_solana_spl_tokens(
|
|
236
|
+
api_key: str, address: str, network: str = "mainnet"
|
|
237
|
+
) -> Dict:
|
|
238
|
+
"""Get SPL token balances.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
api_key: API key for the data provider
|
|
242
|
+
address: Solana wallet address
|
|
243
|
+
network: Solana network (mainnet or devnet)
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
SPL token balances
|
|
247
|
+
"""
|
|
248
|
+
endpoint = f"/account/{network}/{address}/tokens"
|
|
249
|
+
return await fetch_solana_api(api_key, endpoint)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
async def get_solana_nfts(api_key: str, address: str, network: str = "mainnet") -> Dict:
|
|
253
|
+
"""Get NFTs owned by a Solana wallet.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
api_key: API key for the data provider
|
|
257
|
+
address: Solana wallet address
|
|
258
|
+
network: Solana network (mainnet or devnet)
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
NFT holdings
|
|
262
|
+
"""
|
|
263
|
+
endpoint = f"/account/{network}/{address}/nft"
|
|
264
|
+
return await fetch_solana_api(api_key, endpoint)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
async def get_token_price(
|
|
268
|
+
api_key: str, token_address: str, network: str = "mainnet"
|
|
269
|
+
) -> Dict:
|
|
270
|
+
"""Get token price by mint address.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
api_key: API key for the data provider
|
|
274
|
+
token_address: Token mint address
|
|
275
|
+
network: Solana network (mainnet or devnet)
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Token price data
|
|
279
|
+
"""
|
|
280
|
+
endpoint = f"/token/{network}/{token_address}/price"
|
|
281
|
+
return await fetch_solana_api(api_key, endpoint)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Base class for Wallet Portfolio tools."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional, Type
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
8
|
+
from intentkit.skills.base import IntentKitSkill
|
|
9
|
+
|
|
10
|
+
# Chain ID to chain name mapping for EVM chains
|
|
11
|
+
CHAIN_MAPPING = {
|
|
12
|
+
1: "eth",
|
|
13
|
+
56: "bsc",
|
|
14
|
+
137: "polygon",
|
|
15
|
+
42161: "arbitrum",
|
|
16
|
+
10: "optimism",
|
|
17
|
+
43114: "avalanche",
|
|
18
|
+
250: "fantom",
|
|
19
|
+
8453: "base",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Solana networks
|
|
23
|
+
SOLANA_NETWORKS = ["mainnet", "devnet"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WalletBaseTool(IntentKitSkill):
|
|
27
|
+
"""Base class for all wallet portfolio tools."""
|
|
28
|
+
|
|
29
|
+
name: str = Field(description="The name of the tool")
|
|
30
|
+
description: str = Field(description="A description of what the tool does")
|
|
31
|
+
args_schema: Type[BaseModel]
|
|
32
|
+
skill_store: SkillStoreABC = Field(
|
|
33
|
+
description="The skill store for persisting data"
|
|
34
|
+
)
|
|
35
|
+
api_key: str = Field(description="API key for Moralis")
|
|
36
|
+
|
|
37
|
+
# Optional fields for blockchain providers
|
|
38
|
+
solana_networks: Optional[List[str]] = Field(
|
|
39
|
+
default=SOLANA_NETWORKS, description="Supported Solana networks"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def category(self) -> str:
|
|
44
|
+
return "moralis"
|
|
45
|
+
|
|
46
|
+
def _get_chain_name(self, chain_id: int) -> str:
|
|
47
|
+
"""Convert chain ID to chain name for API calls.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
chain_id: The blockchain network ID
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The chain name used by the API
|
|
54
|
+
"""
|
|
55
|
+
return CHAIN_MAPPING.get(chain_id, "eth")
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""fetching wallet portfolio for a specific blockchain."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import List, Optional, Type
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.moralis.api import fetch_token_approvals, fetch_wallet_balances
|
|
9
|
+
from intentkit.skills.moralis.base import WalletBaseTool
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FetchChainPortfolioInput(BaseModel):
|
|
15
|
+
"""Input for FetchChainPortfolio tool."""
|
|
16
|
+
|
|
17
|
+
address: str = Field(..., description="Wallet address")
|
|
18
|
+
chain_id: int = Field(..., description="Chain ID to fetch portfolio for")
|
|
19
|
+
include_approvals: bool = Field(
|
|
20
|
+
default=False, description="Whether to include token approvals in the response"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ChainTokenBalance(BaseModel):
|
|
25
|
+
"""Model for token balance on a specific chain."""
|
|
26
|
+
|
|
27
|
+
contract_address: str = Field(..., description="Token contract address")
|
|
28
|
+
symbol: str = Field(..., description="Token symbol")
|
|
29
|
+
name: str = Field(..., description="Token name")
|
|
30
|
+
logo: Optional[str] = Field(None, description="Token logo URL")
|
|
31
|
+
decimals: int = Field(..., description="Token decimals")
|
|
32
|
+
balance: float = Field(..., description="Token balance")
|
|
33
|
+
balance_raw: str = Field(..., description="Raw token balance")
|
|
34
|
+
balance_usd: float = Field(0.0, description="USD value of token balance")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TokenApproval(BaseModel):
|
|
38
|
+
"""Model for token approval."""
|
|
39
|
+
|
|
40
|
+
token_address: str = Field(..., description="Token contract address")
|
|
41
|
+
token_symbol: Optional[str] = Field(None, description="Token symbol")
|
|
42
|
+
token_name: Optional[str] = Field(None, description="Token name")
|
|
43
|
+
spender: str = Field(..., description="Spender address (contract)")
|
|
44
|
+
spender_name: Optional[str] = Field(None, description="Spender name if known")
|
|
45
|
+
allowance: str = Field(..., description="Raw approval amount")
|
|
46
|
+
allowance_formatted: Optional[float] = Field(
|
|
47
|
+
None, description="Formatted approval amount"
|
|
48
|
+
)
|
|
49
|
+
unlimited: bool = Field(False, description="Whether the approval is unlimited")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ChainPortfolioOutput(BaseModel):
|
|
53
|
+
"""Output for FetchChainPortfolio tool."""
|
|
54
|
+
|
|
55
|
+
address: str = Field(..., description="Wallet address")
|
|
56
|
+
chain_id: int = Field(..., description="Chain ID")
|
|
57
|
+
chain_name: str = Field(..., description="Chain name")
|
|
58
|
+
native_token: Optional[ChainTokenBalance] = Field(
|
|
59
|
+
None, description="Native token balance"
|
|
60
|
+
)
|
|
61
|
+
tokens: List[ChainTokenBalance] = Field(
|
|
62
|
+
default_factory=list, description="List of token balances"
|
|
63
|
+
)
|
|
64
|
+
total_usd_value: float = Field(0.0, description="Total USD value on this chain")
|
|
65
|
+
approvals: Optional[List[TokenApproval]] = Field(
|
|
66
|
+
None, description="Token approvals if requested"
|
|
67
|
+
)
|
|
68
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class FetchChainPortfolio(WalletBaseTool):
|
|
72
|
+
"""Tool for fetching wallet portfolio for a specific blockchain.
|
|
73
|
+
|
|
74
|
+
This tool retrieves detailed information about a wallet's holdings on a specific
|
|
75
|
+
blockchain, including token balances, USD values, and optionally token approvals.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
name: str = "moralis_fetch_chain_portfolio"
|
|
79
|
+
description: str = (
|
|
80
|
+
"This tool fetches wallet portfolio data for a specific blockchain.\n"
|
|
81
|
+
"Provide a wallet address and chain ID to get detailed information about tokens and their values.\n"
|
|
82
|
+
"Returns:\n"
|
|
83
|
+
"- Token balances for the specified chain\n"
|
|
84
|
+
"- USD value of each token\n"
|
|
85
|
+
"- Total chain value\n"
|
|
86
|
+
"- Token metadata (symbol, name, decimals)\n"
|
|
87
|
+
"- Token approvals (optional)\n"
|
|
88
|
+
"Use this tool whenever a user wants to see their holdings on a specific blockchain."
|
|
89
|
+
)
|
|
90
|
+
args_schema: Type[BaseModel] = FetchChainPortfolioInput
|
|
91
|
+
|
|
92
|
+
async def _arun(
|
|
93
|
+
self, address: str, chain_id: int, include_approvals: bool = False, **kwargs
|
|
94
|
+
) -> ChainPortfolioOutput:
|
|
95
|
+
"""Fetch wallet portfolio for a specific chain.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
address: Wallet address to fetch portfolio for
|
|
99
|
+
chain_id: Chain ID to fetch portfolio for
|
|
100
|
+
include_approvals: Whether to include token approvals
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
ChainPortfolioOutput containing portfolio data for the specified chain
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
# Fetch wallet balances for the specified chain
|
|
107
|
+
balances = await fetch_wallet_balances(self.api_key, address, chain_id)
|
|
108
|
+
|
|
109
|
+
if "error" in balances:
|
|
110
|
+
return ChainPortfolioOutput(
|
|
111
|
+
address=address,
|
|
112
|
+
chain_id=chain_id,
|
|
113
|
+
chain_name=self._get_chain_name(chain_id),
|
|
114
|
+
error=balances["error"],
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Process the data
|
|
118
|
+
portfolio = {
|
|
119
|
+
"address": address,
|
|
120
|
+
"chain_id": chain_id,
|
|
121
|
+
"chain_name": self._get_chain_name(chain_id),
|
|
122
|
+
"tokens": [],
|
|
123
|
+
"total_usd_value": 0.0,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for token in balances.get("result", []):
|
|
127
|
+
token_balance = ChainTokenBalance(
|
|
128
|
+
contract_address=token["token_address"],
|
|
129
|
+
symbol=token.get("symbol", "UNKNOWN"),
|
|
130
|
+
name=token.get("name", "Unknown Token"),
|
|
131
|
+
logo=token.get("logo", None),
|
|
132
|
+
decimals=token.get("decimals", 18),
|
|
133
|
+
balance=float(token.get("balance_formatted", 0)),
|
|
134
|
+
balance_raw=token.get("balance", "0"),
|
|
135
|
+
balance_usd=float(token.get("usd_value", 0)),
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Identify native token
|
|
139
|
+
if token.get("native_token", False):
|
|
140
|
+
portfolio["native_token"] = token_balance
|
|
141
|
+
else:
|
|
142
|
+
portfolio["tokens"].append(token_balance)
|
|
143
|
+
|
|
144
|
+
# Add to total USD value
|
|
145
|
+
portfolio["total_usd_value"] += token_balance.balance_usd
|
|
146
|
+
|
|
147
|
+
# Fetch token approvals if requested
|
|
148
|
+
if include_approvals:
|
|
149
|
+
approvals_data = await fetch_token_approvals(
|
|
150
|
+
self.api_key, address, chain_id
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if "error" not in approvals_data:
|
|
154
|
+
approvals = []
|
|
155
|
+
|
|
156
|
+
for approval in approvals_data.get("result", []):
|
|
157
|
+
# Determine if the approval is unlimited (max uint256)
|
|
158
|
+
allowance = approval.get("allowance", "0")
|
|
159
|
+
is_unlimited = (
|
|
160
|
+
allowance
|
|
161
|
+
== "115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Create approval object
|
|
165
|
+
token_approval = TokenApproval(
|
|
166
|
+
token_address=approval.get("token_address", ""),
|
|
167
|
+
token_symbol=approval.get("token_symbol"),
|
|
168
|
+
token_name=approval.get("token_name"),
|
|
169
|
+
spender=approval.get("spender", ""),
|
|
170
|
+
spender_name=approval.get("spender_name"),
|
|
171
|
+
allowance=allowance,
|
|
172
|
+
allowance_formatted=float(
|
|
173
|
+
approval.get("allowance_formatted", 0)
|
|
174
|
+
),
|
|
175
|
+
unlimited=is_unlimited,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
approvals.append(token_approval)
|
|
179
|
+
|
|
180
|
+
portfolio["approvals"] = approvals
|
|
181
|
+
|
|
182
|
+
return ChainPortfolioOutput(**portfolio)
|
|
183
|
+
|
|
184
|
+
except Exception as e:
|
|
185
|
+
logger.error(f"Error fetching chain portfolio: {str(e)}")
|
|
186
|
+
return ChainPortfolioOutput(
|
|
187
|
+
address=address,
|
|
188
|
+
chain_id=chain_id,
|
|
189
|
+
chain_name=self._get_chain_name(chain_id),
|
|
190
|
+
error=str(e),
|
|
191
|
+
)
|