intentkit 0.7.5.dev3__py3-none-any.whl → 0.8.34.dev7__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.
- intentkit/MANIFEST.in +14 -0
- intentkit/README.md +88 -0
- intentkit/__init__.py +6 -4
- intentkit/abstracts/agent.py +4 -5
- intentkit/abstracts/engine.py +5 -5
- intentkit/abstracts/graph.py +15 -8
- intentkit/abstracts/skill.py +6 -144
- intentkit/abstracts/twitter.py +4 -5
- intentkit/clients/__init__.py +9 -2
- intentkit/clients/cdp.py +129 -153
- intentkit/{utils → clients}/s3.py +109 -34
- intentkit/clients/twitter.py +83 -62
- intentkit/clients/web3.py +4 -7
- intentkit/config/config.py +123 -90
- intentkit/core/account_checking.py +802 -0
- intentkit/core/agent.py +313 -498
- intentkit/core/asset.py +267 -0
- intentkit/core/chat.py +5 -3
- intentkit/core/client.py +1 -1
- intentkit/core/credit.py +49 -41
- intentkit/core/draft.py +201 -0
- intentkit/core/draft_chat.py +118 -0
- intentkit/core/engine.py +378 -287
- intentkit/core/manager/__init__.py +25 -0
- intentkit/core/manager/engine.py +220 -0
- intentkit/core/manager/service.py +172 -0
- intentkit/core/manager/skills.py +178 -0
- intentkit/core/middleware.py +231 -0
- intentkit/core/prompt.py +74 -114
- intentkit/core/scheduler.py +143 -0
- intentkit/core/statistics.py +168 -0
- intentkit/models/agent.py +931 -518
- intentkit/models/agent_data.py +165 -106
- intentkit/models/agent_schema.json +38 -251
- intentkit/models/app_setting.py +15 -13
- intentkit/models/chat.py +86 -140
- intentkit/models/credit.py +182 -162
- intentkit/models/db.py +42 -23
- intentkit/models/db_mig.py +120 -3
- intentkit/models/draft.py +222 -0
- intentkit/models/llm.csv +31 -0
- intentkit/models/llm.py +262 -370
- intentkit/models/redis.py +6 -4
- intentkit/models/skill.py +222 -101
- intentkit/models/skills.csv +173 -0
- intentkit/models/team.py +189 -0
- intentkit/models/user.py +103 -31
- 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 +241 -41
- 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 +6 -6
- intentkit/skills/casino/__init__.py +4 -15
- intentkit/skills/casino/base.py +1 -7
- intentkit/skills/casino/deck_draw.py +5 -8
- intentkit/skills/casino/deck_shuffle.py +6 -6
- intentkit/skills/casino/dice_roll.py +2 -4
- intentkit/skills/casino/schema.json +0 -1
- 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 +10 -24
- 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 +8 -19
- 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/__init__.py +97 -102
- intentkit/skills/dexscreener/base.py +125 -130
- intentkit/skills/dexscreener/get_pair_info.py +4 -5
- intentkit/skills/dexscreener/get_token_pairs.py +4 -5
- intentkit/skills/dexscreener/get_tokens_info.py +7 -8
- intentkit/skills/dexscreener/model/search_token_response.py +80 -82
- intentkit/skills/dexscreener/schema.json +91 -93
- intentkit/skills/dexscreener/search_token.py +182 -184
- intentkit/skills/dexscreener/utils.py +15 -14
- 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 +54 -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/__init__.py +5 -18
- intentkit/skills/firecrawl/base.py +4 -9
- 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 +2 -6
- intentkit/skills/firecrawl/scrape.py +17 -22
- 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 +13 -15
- intentkit/skills/heurist/image_generation_arthemy_comics.py +13 -15
- intentkit/skills/heurist/image_generation_arthemy_real.py +13 -15
- intentkit/skills/heurist/image_generation_braindance.py +13 -15
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +13 -15
- intentkit/skills/heurist/image_generation_flux_1_dev.py +13 -15
- intentkit/skills/heurist/image_generation_sdxl.py +13 -15
- 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 +3 -9
- intentkit/skills/lifi/schema.json +17 -8
- intentkit/skills/lifi/token_execute.py +150 -60
- 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 +30 -0
- intentkit/skills/openai/__init__.py +17 -18
- intentkit/skills/openai/base.py +10 -14
- intentkit/skills/openai/dalle_image_generation.py +4 -9
- intentkit/skills/openai/gpt_avatar_generator.py +102 -0
- intentkit/skills/openai/gpt_image_generation.py +5 -9
- intentkit/skills/openai/gpt_image_mini_generator.py +92 -0
- intentkit/skills/openai/gpt_image_to_image.py +5 -9
- 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 +36 -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 +1 -7
- intentkit/skills/supabase/delete_data.py +4 -4
- intentkit/skills/supabase/fetch_data.py +12 -12
- intentkit/skills/supabase/insert_data.py +4 -4
- intentkit/skills/supabase/invoke_function.py +6 -6
- intentkit/skills/supabase/schema.json +2 -3
- intentkit/skills/supabase/update_data.py +6 -6
- intentkit/skills/supabase/upsert_data.py +4 -4
- 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 +22 -34
- intentkit/skills/twitter/follow_user.py +2 -6
- intentkit/skills/twitter/get_mentions.py +5 -12
- intentkit/skills/twitter/get_timeline.py +4 -12
- intentkit/skills/twitter/get_user_by_username.py +2 -6
- intentkit/skills/twitter/get_user_tweets.py +5 -13
- intentkit/skills/twitter/like_tweet.py +2 -6
- intentkit/skills/twitter/post_tweet.py +6 -9
- intentkit/skills/twitter/reply_tweet.py +6 -9
- intentkit/skills/twitter/retweet.py +2 -6
- intentkit/skills/twitter/schema.json +1 -0
- intentkit/skills/twitter/search_tweets.py +4 -12
- 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 +11 -10
- 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 +58 -0
- intentkit/skills/x402/base.py +99 -0
- intentkit/skills/x402/http_request.py +117 -0
- intentkit/skills/x402/schema.json +40 -0
- intentkit/skills/x402/x402.webp +0 -0
- intentkit/skills/xmtp/__init__.py +4 -15
- intentkit/skills/xmtp/base.py +5 -5
- intentkit/skills/xmtp/price.py +7 -6
- intentkit/skills/xmtp/schema.json +69 -71
- intentkit/skills/xmtp/swap.py +6 -8
- intentkit/skills/xmtp/transfer.py +4 -6
- intentkit/utils/__init__.py +4 -0
- intentkit/utils/chain.py +198 -96
- intentkit/utils/ens.py +135 -0
- intentkit/utils/error.py +5 -2
- intentkit/utils/logging.py +9 -11
- intentkit/utils/schema.py +100 -0
- intentkit/utils/slack_alert.py +8 -8
- intentkit/utils/tx.py +16 -8
- intentkit/uv.lock +3377 -0
- {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/METADATA +13 -15
- intentkit-0.8.34.dev7.dist-info/RECORD +478 -0
- intentkit-0.8.34.dev7.dist-info/licenses/LICENSE +21 -0
- intentkit/core/node.py +0 -215
- intentkit/models/conversation.py +0 -286
- 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.7.5.dev3.dist-info/RECORD +0 -424
- {intentkit-0.7.5.dev3.dist-info/licenses → intentkit}/LICENSE +0 -0
- {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/WHEEL +0 -0
intentkit/skills/http/put.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
7
8
|
from intentkit.skills.http.base import HttpBaseTool
|
|
@@ -13,19 +14,19 @@ class HttpPutInput(BaseModel):
|
|
|
13
14
|
"""Input for HTTP PUT request."""
|
|
14
15
|
|
|
15
16
|
url: str = Field(description="The URL to send the PUT request to")
|
|
16
|
-
data:
|
|
17
|
+
data: dict[str, Any] | str | None = Field(
|
|
17
18
|
description="The data to send in the request body. Can be a dictionary (will be sent as JSON) or a string",
|
|
18
19
|
default=None,
|
|
19
20
|
)
|
|
20
|
-
headers:
|
|
21
|
+
headers: dict[str, str] | None = Field(
|
|
21
22
|
description="Optional headers to include in the request",
|
|
22
23
|
default=None,
|
|
23
24
|
)
|
|
24
|
-
params:
|
|
25
|
+
params: dict[str, Any] | None = Field(
|
|
25
26
|
description="Optional query parameters to include in the request",
|
|
26
27
|
default=None,
|
|
27
28
|
)
|
|
28
|
-
timeout:
|
|
29
|
+
timeout: float | None = Field(
|
|
29
30
|
description="Request timeout in seconds (default: 30)",
|
|
30
31
|
default=30.0,
|
|
31
32
|
)
|
|
@@ -51,14 +52,14 @@ class HttpPut(HttpBaseTool):
|
|
|
51
52
|
"Returns the response content as text. "
|
|
52
53
|
"Use this when you need to update or replace data on web APIs."
|
|
53
54
|
)
|
|
54
|
-
args_schema:
|
|
55
|
+
args_schema: type[BaseModel] = HttpPutInput
|
|
55
56
|
|
|
56
57
|
async def _arun(
|
|
57
58
|
self,
|
|
58
59
|
url: str,
|
|
59
|
-
data:
|
|
60
|
-
headers:
|
|
61
|
-
params:
|
|
60
|
+
data: dict[str, Any] | str | None = None,
|
|
61
|
+
headers: dict[str, str] | None = None,
|
|
62
|
+
params: dict[str, Any] | None = None,
|
|
62
63
|
timeout: float = 30.0,
|
|
63
64
|
**kwargs,
|
|
64
65
|
) -> str:
|
|
@@ -100,12 +101,16 @@ class HttpPut(HttpBaseTool):
|
|
|
100
101
|
# Return response content
|
|
101
102
|
return f"Status: {response.status_code}\nContent: {response.text}"
|
|
102
103
|
|
|
103
|
-
except httpx.TimeoutException:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
except httpx.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
104
|
+
except httpx.TimeoutException as exc:
|
|
105
|
+
raise ToolException(
|
|
106
|
+
f"Request to {url} timed out after {timeout} seconds"
|
|
107
|
+
) from exc
|
|
108
|
+
except httpx.HTTPStatusError as exc:
|
|
109
|
+
raise ToolException(
|
|
110
|
+
f"HTTP {exc.response.status_code} - {exc.response.text}"
|
|
111
|
+
) from exc
|
|
112
|
+
except httpx.RequestError as exc:
|
|
113
|
+
raise ToolException(f"Failed to connect to {url} - {str(exc)}") from exc
|
|
114
|
+
except Exception as exc: # noqa: BLE001
|
|
115
|
+
logger.error("Unexpected error in HTTP PUT request", exc_info=exc)
|
|
116
|
+
raise ToolException(f"Unexpected error occurred - {str(exc)}") from exc
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
"description": "HTTP client skills for making web requests",
|
|
6
6
|
"x-icon": "https://ai.service.crestal.dev/skills/http/http.svg",
|
|
7
7
|
"x-tags": [
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"Client"
|
|
8
|
+
"Developer Tools",
|
|
9
|
+
"Infrastructure",
|
|
10
|
+
"Knowledge Base"
|
|
12
11
|
],
|
|
13
12
|
"properties": {
|
|
14
13
|
"enabled": {
|
|
@@ -77,4 +76,4 @@
|
|
|
77
76
|
"enabled"
|
|
78
77
|
],
|
|
79
78
|
"additionalProperties": true
|
|
80
|
-
}
|
|
79
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any, TypedDict
|
|
3
3
|
|
|
4
|
-
from intentkit.abstracts.skill import SkillStoreABC
|
|
5
4
|
from intentkit.skills.base import SkillConfig, SkillState
|
|
6
5
|
from intentkit.skills.lifi.base import LiFiBaseTool
|
|
7
6
|
from intentkit.skills.lifi.token_execute import TokenExecute
|
|
@@ -23,19 +22,18 @@ class Config(SkillConfig):
|
|
|
23
22
|
"""Configuration for LiFi skills."""
|
|
24
23
|
|
|
25
24
|
states: SkillStates
|
|
26
|
-
default_slippage:
|
|
27
|
-
allowed_chains:
|
|
28
|
-
max_execution_time:
|
|
25
|
+
default_slippage: float | None = 0.03
|
|
26
|
+
allowed_chains: list[str] | None = None
|
|
27
|
+
max_execution_time: int | None = 300
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
async def get_skills(
|
|
32
31
|
config: "Config",
|
|
33
32
|
is_private: bool,
|
|
34
|
-
|
|
35
|
-
**_,
|
|
33
|
+
**_: Any,
|
|
36
34
|
) -> list[LiFiBaseTool]:
|
|
37
35
|
"""Get all LiFi skills."""
|
|
38
|
-
available_skills = []
|
|
36
|
+
available_skills: list[str] = []
|
|
39
37
|
|
|
40
38
|
# Log configuration
|
|
41
39
|
logger.info(f"[LiFi_Skills] Initializing with config: {config}")
|
|
@@ -57,10 +55,10 @@ async def get_skills(
|
|
|
57
55
|
logger.info(f"[LiFi_Skills] Available skills: {available_skills}")
|
|
58
56
|
|
|
59
57
|
# Get each skill using the cached getter
|
|
60
|
-
skills = []
|
|
58
|
+
skills: list[LiFiBaseTool] = []
|
|
61
59
|
for name in available_skills:
|
|
62
60
|
try:
|
|
63
|
-
skill = get_lifi_skill(name,
|
|
61
|
+
skill = get_lifi_skill(name, config)
|
|
64
62
|
skills.append(skill)
|
|
65
63
|
logger.info(f"[LiFi_Skills] Successfully loaded skill: {name}")
|
|
66
64
|
except Exception as e:
|
|
@@ -73,7 +71,6 @@ async def get_skills(
|
|
|
73
71
|
|
|
74
72
|
def get_lifi_skill(
|
|
75
73
|
name: str,
|
|
76
|
-
store: SkillStoreABC,
|
|
77
74
|
config: Config,
|
|
78
75
|
) -> LiFiBaseTool:
|
|
79
76
|
"""Get a LiFi skill by name."""
|
|
@@ -108,7 +105,6 @@ def get_lifi_skill(
|
|
|
108
105
|
logger.info(f"[LiFi_Skills] Allowed chains: {allowed_chains}")
|
|
109
106
|
|
|
110
107
|
_cache[cache_key] = TokenQuote(
|
|
111
|
-
skill_store=store,
|
|
112
108
|
default_slippage=default_slippage,
|
|
113
109
|
allowed_chains=allowed_chains,
|
|
114
110
|
)
|
|
@@ -129,7 +125,6 @@ def get_lifi_skill(
|
|
|
129
125
|
)
|
|
130
126
|
|
|
131
127
|
_cache[cache_key] = TokenExecute(
|
|
132
|
-
skill_store=store,
|
|
133
128
|
default_slippage=default_slippage,
|
|
134
129
|
allowed_chains=allowed_chains,
|
|
135
130
|
max_execution_time=max_execution_time,
|
intentkit/skills/lifi/base.py
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
from typing import Type
|
|
2
|
-
|
|
3
1
|
from pydantic import BaseModel, Field
|
|
4
2
|
|
|
5
|
-
from intentkit.
|
|
6
|
-
from intentkit.skills.base import IntentKitSkill
|
|
3
|
+
from intentkit.skills.onchain import IntentKitOnChainSkill
|
|
7
4
|
|
|
8
5
|
|
|
9
|
-
class LiFiBaseTool(
|
|
6
|
+
class LiFiBaseTool(IntentKitOnChainSkill):
|
|
10
7
|
"""Base class for LiFi tools."""
|
|
11
8
|
|
|
12
9
|
name: str = Field(description="The name of the tool")
|
|
13
10
|
description: str = Field(description="A description of what the tool does")
|
|
14
|
-
args_schema:
|
|
15
|
-
skill_store: SkillStoreABC = Field(
|
|
16
|
-
description="The skill store for persisting data"
|
|
17
|
-
)
|
|
11
|
+
args_schema: type[BaseModel]
|
|
18
12
|
|
|
19
13
|
@property
|
|
20
14
|
def category(self) -> str:
|
|
@@ -5,10 +5,7 @@
|
|
|
5
5
|
"description": "Cross-chain token transfer and swap capabilities using the LiFi protocol",
|
|
6
6
|
"x-icon": "https://ai.service.crestal.dev/skills/lifi/lifi.png",
|
|
7
7
|
"x-tags": [
|
|
8
|
-
"DeFi"
|
|
9
|
-
"Blockchain",
|
|
10
|
-
"Token Transfer",
|
|
11
|
-
"Cross-chain"
|
|
8
|
+
"DeFi"
|
|
12
9
|
],
|
|
13
10
|
"properties": {
|
|
14
11
|
"enabled": {
|
|
@@ -53,7 +50,10 @@
|
|
|
53
50
|
"description": "Execute token transfers (requires CDP wallet and cdp skills enabled)"
|
|
54
51
|
}
|
|
55
52
|
},
|
|
56
|
-
"required": [
|
|
53
|
+
"required": [
|
|
54
|
+
"token_quote",
|
|
55
|
+
"token_execute"
|
|
56
|
+
],
|
|
57
57
|
"description": "States for each LiFi skill"
|
|
58
58
|
},
|
|
59
59
|
"default_slippage": {
|
|
@@ -71,7 +71,13 @@
|
|
|
71
71
|
"description": "List of blockchain networks that can be used (if empty, all supported chains are allowed)",
|
|
72
72
|
"items": {
|
|
73
73
|
"type": "string",
|
|
74
|
-
"examples": [
|
|
74
|
+
"examples": [
|
|
75
|
+
"ETH",
|
|
76
|
+
"POL",
|
|
77
|
+
"ARB",
|
|
78
|
+
"OPT",
|
|
79
|
+
"DAI"
|
|
80
|
+
]
|
|
75
81
|
},
|
|
76
82
|
"uniqueItems": true
|
|
77
83
|
},
|
|
@@ -84,6 +90,9 @@
|
|
|
84
90
|
"maximum": 1800
|
|
85
91
|
}
|
|
86
92
|
},
|
|
87
|
-
"required": [
|
|
93
|
+
"required": [
|
|
94
|
+
"states",
|
|
95
|
+
"enabled"
|
|
96
|
+
],
|
|
88
97
|
"additionalProperties": true
|
|
89
|
-
}
|
|
98
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
|
+
from cdp import EvmServerAccount, TransactionRequestEIP1559
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
from web3 import Web3
|
|
8
|
+
from web3.exceptions import TimeExhausted
|
|
7
9
|
|
|
8
|
-
from intentkit.abstracts.skill import SkillStoreABC
|
|
9
|
-
from intentkit.clients import get_cdp_client
|
|
10
10
|
from intentkit.skills.lifi.base import LiFiBaseTool
|
|
11
11
|
from intentkit.skills.lifi.token_quote import TokenQuote
|
|
12
12
|
from intentkit.skills.lifi.utils import (
|
|
@@ -22,6 +22,7 @@ from intentkit.skills.lifi.utils import (
|
|
|
22
22
|
prepare_transaction_params,
|
|
23
23
|
validate_inputs,
|
|
24
24
|
)
|
|
25
|
+
from intentkit.utils.error import IntentKitAPIError
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class TokenExecuteInput(BaseModel):
|
|
@@ -51,7 +52,7 @@ class TokenExecuteInput(BaseModel):
|
|
|
51
52
|
class TokenExecute(LiFiBaseTool):
|
|
52
53
|
"""Tool for executing token transfers across chains using LiFi.
|
|
53
54
|
|
|
54
|
-
This tool executes actual token transfers and swaps using the CDP
|
|
55
|
+
This tool executes actual token transfers and swaps using the CDP EVM account.
|
|
55
56
|
Requires a properly configured CDP wallet to work.
|
|
56
57
|
"""
|
|
57
58
|
|
|
@@ -62,37 +63,37 @@ class TokenExecute(LiFiBaseTool):
|
|
|
62
63
|
"Use token_quote first to check rates and fees before executing.\n"
|
|
63
64
|
"Supports all major chains like Ethereum, Polygon, Arbitrum, Optimism, Base, and more."
|
|
64
65
|
)
|
|
65
|
-
args_schema:
|
|
66
|
+
args_schema: type[BaseModel] = TokenExecuteInput
|
|
66
67
|
api_url: str = LIFI_API_URL
|
|
67
68
|
|
|
68
69
|
# Configuration options
|
|
69
70
|
default_slippage: float = 0.03
|
|
70
|
-
allowed_chains:
|
|
71
|
+
allowed_chains: list[str] | None = None
|
|
71
72
|
max_execution_time: int = 300
|
|
72
|
-
quote_tool: TokenQuote = Field(default=None, exclude=True)
|
|
73
|
+
quote_tool: TokenQuote | None = Field(default=None, exclude=True)
|
|
73
74
|
|
|
74
75
|
def __init__(
|
|
75
76
|
self,
|
|
76
|
-
skill_store: SkillStoreABC,
|
|
77
77
|
default_slippage: float = 0.03,
|
|
78
|
-
allowed_chains:
|
|
78
|
+
allowed_chains: list[str] | None = None,
|
|
79
79
|
max_execution_time: int = 300,
|
|
80
|
-
):
|
|
80
|
+
) -> None:
|
|
81
81
|
"""Initialize the TokenExecute skill with configuration options."""
|
|
82
|
-
super().__init__(
|
|
82
|
+
super().__init__()
|
|
83
83
|
self.default_slippage = default_slippage
|
|
84
84
|
self.allowed_chains = allowed_chains
|
|
85
85
|
self.max_execution_time = max_execution_time
|
|
86
86
|
# Initialize quote tool if not set
|
|
87
87
|
if not self.quote_tool:
|
|
88
88
|
self.quote_tool = TokenQuote(
|
|
89
|
-
skill_store=skill_store,
|
|
90
89
|
default_slippage=default_slippage,
|
|
91
90
|
allowed_chains=allowed_chains,
|
|
92
91
|
)
|
|
93
92
|
|
|
94
|
-
def _format_quote_result(self, data:
|
|
93
|
+
def _format_quote_result(self, data: dict[str, Any]) -> str:
|
|
95
94
|
"""Format the quote result in a readable format."""
|
|
95
|
+
if self.quote_tool is None:
|
|
96
|
+
raise RuntimeError("Quote tool is not initialized")
|
|
96
97
|
# Use the same formatting as token_quote
|
|
97
98
|
return self.quote_tool._format_quote_result(data)
|
|
98
99
|
|
|
@@ -103,7 +104,7 @@ class TokenExecute(LiFiBaseTool):
|
|
|
103
104
|
from_token: str,
|
|
104
105
|
to_token: str,
|
|
105
106
|
from_amount: str,
|
|
106
|
-
slippage: float = None,
|
|
107
|
+
slippage: float | None = None,
|
|
107
108
|
**kwargs,
|
|
108
109
|
) -> str:
|
|
109
110
|
"""Execute a token transfer."""
|
|
@@ -127,22 +128,36 @@ class TokenExecute(LiFiBaseTool):
|
|
|
127
128
|
|
|
128
129
|
# Get agent context for CDP wallet
|
|
129
130
|
context = self.get_context()
|
|
130
|
-
|
|
131
|
+
agent = context.agent
|
|
132
|
+
network_id = agent.network_id
|
|
133
|
+
if not network_id:
|
|
134
|
+
return "Agent network ID is not configured. Please set it before executing on-chain transactions."
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
cdp_network = self.get_cdp_network()
|
|
138
|
+
except Exception as e:
|
|
139
|
+
self.logger.error("LiFi_CDP_Network_Error: %s", str(e))
|
|
140
|
+
return f"Invalid agent network for CDP: {str(e)}"
|
|
131
141
|
|
|
132
142
|
self.logger.info(
|
|
133
143
|
f"Executing LiFi transfer: {from_amount} {from_token} on {from_chain} -> {to_token} on {to_chain}"
|
|
134
144
|
)
|
|
135
145
|
|
|
136
|
-
# Get CDP
|
|
137
|
-
|
|
138
|
-
if isinstance(
|
|
139
|
-
return
|
|
146
|
+
# Get CDP EVM account and web3 client
|
|
147
|
+
evm_account = await self._get_evm_account()
|
|
148
|
+
if isinstance(evm_account, str): # Error message
|
|
149
|
+
return evm_account
|
|
140
150
|
|
|
141
|
-
|
|
142
|
-
from_address = cdp_wallet_provider.get_address()
|
|
151
|
+
from_address = evm_account.address
|
|
143
152
|
if not from_address:
|
|
144
153
|
return "No wallet address available. Please check your CDP wallet configuration."
|
|
145
154
|
|
|
155
|
+
try:
|
|
156
|
+
web3 = self.web3_client()
|
|
157
|
+
except Exception as e:
|
|
158
|
+
self.logger.error("LiFi_Web3_Error: %s", str(e))
|
|
159
|
+
return "Unable to initialize Web3 client. Please verify the agent's network configuration."
|
|
160
|
+
|
|
146
161
|
# Get quote and execute transfer
|
|
147
162
|
async with httpx.AsyncClient() as client:
|
|
148
163
|
# Step 1: Get quote
|
|
@@ -161,14 +176,22 @@ class TokenExecute(LiFiBaseTool):
|
|
|
161
176
|
|
|
162
177
|
# Step 2: Handle token approval if needed
|
|
163
178
|
approval_result = await self._handle_token_approval(
|
|
164
|
-
|
|
179
|
+
evm_account,
|
|
180
|
+
quote_data,
|
|
181
|
+
web3,
|
|
182
|
+
cdp_network,
|
|
183
|
+
from_address,
|
|
165
184
|
)
|
|
166
185
|
if approval_result:
|
|
167
186
|
self.logger.info(f"Token approval completed: {approval_result}")
|
|
168
187
|
|
|
169
188
|
# Step 3: Execute transaction
|
|
170
189
|
tx_hash = await self._execute_transfer_transaction(
|
|
171
|
-
|
|
190
|
+
evm_account,
|
|
191
|
+
quote_data,
|
|
192
|
+
from_address,
|
|
193
|
+
cdp_network,
|
|
194
|
+
web3,
|
|
172
195
|
)
|
|
173
196
|
|
|
174
197
|
# Step 4: Monitor status and return result
|
|
@@ -180,19 +203,18 @@ class TokenExecute(LiFiBaseTool):
|
|
|
180
203
|
self.logger.error("LiFi_Error: %s", str(e))
|
|
181
204
|
return f"An unexpected error occurred: {str(e)}"
|
|
182
205
|
|
|
183
|
-
async def
|
|
184
|
-
"""Get CDP
|
|
206
|
+
async def _get_evm_account(self) -> EvmServerAccount | str:
|
|
207
|
+
"""Get CDP EVM account with error handling."""
|
|
185
208
|
try:
|
|
186
|
-
|
|
187
|
-
if not
|
|
188
|
-
return "CDP
|
|
209
|
+
evm_account = await self.get_evm_account()
|
|
210
|
+
if not evm_account:
|
|
211
|
+
return "CDP wallet account not configured. Please set up your agent's CDP wallet first."
|
|
189
212
|
|
|
190
|
-
|
|
191
|
-
if not cdp_wallet_provider:
|
|
192
|
-
return "CDP wallet provider not configured. Please set up your agent's CDP wallet first."
|
|
193
|
-
|
|
194
|
-
return cdp_wallet_provider
|
|
213
|
+
return evm_account
|
|
195
214
|
|
|
215
|
+
except IntentKitAPIError as e:
|
|
216
|
+
self.logger.error("LiFi_CDP_Error: %s", str(e))
|
|
217
|
+
return f"Cannot access CDP wallet: {str(e)}\n\nPlease ensure your agent has a properly configured CDP wallet with sufficient funds."
|
|
196
218
|
except Exception as e:
|
|
197
219
|
self.logger.error("LiFi_CDP_Error: %s", str(e))
|
|
198
220
|
return f"Cannot access CDP wallet: {str(e)}\n\nPlease ensure your agent has a properly configured CDP wallet with sufficient funds."
|
|
@@ -207,7 +229,7 @@ class TokenExecute(LiFiBaseTool):
|
|
|
207
229
|
from_amount: str,
|
|
208
230
|
slippage: float,
|
|
209
231
|
from_address: str,
|
|
210
|
-
) ->
|
|
232
|
+
) -> dict[str, Any] | str:
|
|
211
233
|
"""Get quote from LiFi API."""
|
|
212
234
|
api_params = build_quote_params(
|
|
213
235
|
from_chain,
|
|
@@ -249,8 +271,13 @@ class TokenExecute(LiFiBaseTool):
|
|
|
249
271
|
return data
|
|
250
272
|
|
|
251
273
|
async def _handle_token_approval(
|
|
252
|
-
self,
|
|
253
|
-
|
|
274
|
+
self,
|
|
275
|
+
evm_account: EvmServerAccount,
|
|
276
|
+
quote_data: dict[str, Any],
|
|
277
|
+
web3: Web3,
|
|
278
|
+
network_id: str,
|
|
279
|
+
wallet_address: str,
|
|
280
|
+
) -> str | None:
|
|
254
281
|
"""Handle ERC20 token approval if needed."""
|
|
255
282
|
estimate = quote_data.get("estimate", {})
|
|
256
283
|
approval_address = estimate.get("approvalAddress")
|
|
@@ -266,30 +293,44 @@ class TokenExecute(LiFiBaseTool):
|
|
|
266
293
|
|
|
267
294
|
try:
|
|
268
295
|
return await self._check_and_set_allowance(
|
|
269
|
-
|
|
296
|
+
evm_account,
|
|
297
|
+
from_token_address,
|
|
298
|
+
approval_address,
|
|
299
|
+
from_amount,
|
|
300
|
+
web3,
|
|
301
|
+
network_id,
|
|
302
|
+
wallet_address,
|
|
270
303
|
)
|
|
271
304
|
except Exception as e:
|
|
272
305
|
self.logger.error("LiFi_Token_Approval_Error: %s", str(e))
|
|
273
306
|
raise Exception(f"Failed to approve token: {str(e)}")
|
|
274
307
|
|
|
275
308
|
async def _execute_transfer_transaction(
|
|
276
|
-
self,
|
|
309
|
+
self,
|
|
310
|
+
evm_account: EvmServerAccount,
|
|
311
|
+
quote_data: dict[str, Any],
|
|
312
|
+
from_address: str,
|
|
313
|
+
network_id: str,
|
|
314
|
+
web3: Web3,
|
|
277
315
|
) -> str:
|
|
278
316
|
"""Execute the main transfer transaction."""
|
|
279
317
|
transaction_request = quote_data.get("transactionRequest")
|
|
280
318
|
|
|
281
319
|
try:
|
|
282
|
-
tx_params = prepare_transaction_params(
|
|
320
|
+
tx_params = prepare_transaction_params(
|
|
321
|
+
transaction_request, wallet_address=from_address
|
|
322
|
+
)
|
|
323
|
+
tx_request = self._build_transaction_request(tx_params)
|
|
283
324
|
self.logger.info(
|
|
284
|
-
f"Sending transaction to {tx_params['to']} with value {tx_params
|
|
325
|
+
f"Sending transaction to {tx_params['to']} with value {tx_params.get('value', 0)}"
|
|
285
326
|
)
|
|
286
327
|
|
|
287
328
|
# Send transaction
|
|
288
|
-
tx_hash =
|
|
329
|
+
tx_hash = await evm_account.send_transaction(tx_request, network=network_id)
|
|
289
330
|
|
|
290
331
|
# Wait for confirmation
|
|
291
|
-
receipt =
|
|
292
|
-
if not receipt or receipt.get("status")
|
|
332
|
+
receipt = await self._wait_for_receipt(web3, tx_hash)
|
|
333
|
+
if not receipt or receipt.get("status") != 1:
|
|
293
334
|
raise Exception(f"Transaction failed: {tx_hash}")
|
|
294
335
|
|
|
295
336
|
return tx_hash
|
|
@@ -298,13 +339,59 @@ class TokenExecute(LiFiBaseTool):
|
|
|
298
339
|
self.logger.error("LiFi_Execution_Error: %s", str(e))
|
|
299
340
|
raise Exception(f"Failed to execute transaction: {str(e)}")
|
|
300
341
|
|
|
342
|
+
def _build_transaction_request(
|
|
343
|
+
self, tx_params: dict[str, Any]
|
|
344
|
+
) -> TransactionRequestEIP1559:
|
|
345
|
+
"""Convert prepared transaction parameters to an EIP-1559 request."""
|
|
346
|
+
request_kwargs: dict[str, Any] = {
|
|
347
|
+
"to": Web3.to_checksum_address(tx_params["to"]),
|
|
348
|
+
"data": tx_params.get("data", "0x"),
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
for key in ("value", "gas", "maxPriorityFeePerGas", "nonce", "chainId"):
|
|
352
|
+
value = tx_params.get(key)
|
|
353
|
+
if value is not None:
|
|
354
|
+
request_kwargs[key] = value
|
|
355
|
+
|
|
356
|
+
max_fee_per_gas = tx_params.get("maxFeePerGas") or tx_params.get("gasPrice")
|
|
357
|
+
if max_fee_per_gas is not None:
|
|
358
|
+
request_kwargs["maxFeePerGas"] = max_fee_per_gas
|
|
359
|
+
|
|
360
|
+
return TransactionRequestEIP1559(**request_kwargs)
|
|
361
|
+
|
|
362
|
+
async def _wait_for_receipt(
|
|
363
|
+
self, web3: Web3, tx_hash: str
|
|
364
|
+
) -> dict[str, Any] | None:
|
|
365
|
+
"""Wait for a transaction receipt using Web3 in a non-blocking way."""
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
receipt = await asyncio.to_thread(
|
|
369
|
+
web3.eth.wait_for_transaction_receipt, tx_hash
|
|
370
|
+
)
|
|
371
|
+
except TimeExhausted as exc:
|
|
372
|
+
self.logger.error("LiFi_Execution_Error: %s", str(exc))
|
|
373
|
+
raise Exception(
|
|
374
|
+
f"Transaction not confirmed before timeout: {tx_hash}"
|
|
375
|
+
) from exc
|
|
376
|
+
except Exception as exc:
|
|
377
|
+
self.logger.error("LiFi_Execution_Error: %s", str(exc))
|
|
378
|
+
raise
|
|
379
|
+
|
|
380
|
+
if receipt is None:
|
|
381
|
+
return None
|
|
382
|
+
|
|
383
|
+
if isinstance(receipt, dict):
|
|
384
|
+
return receipt
|
|
385
|
+
|
|
386
|
+
return dict(receipt)
|
|
387
|
+
|
|
301
388
|
async def _finalize_transfer(
|
|
302
389
|
self,
|
|
303
390
|
client: httpx.AsyncClient,
|
|
304
391
|
tx_hash: str,
|
|
305
392
|
from_chain: str,
|
|
306
393
|
to_chain: str,
|
|
307
|
-
quote_data:
|
|
394
|
+
quote_data: dict[str, Any],
|
|
308
395
|
) -> str:
|
|
309
396
|
"""Finalize transfer and return formatted result."""
|
|
310
397
|
self.logger.info(f"Transaction sent: {tx_hash}")
|
|
@@ -407,25 +494,27 @@ class TokenExecute(LiFiBaseTool):
|
|
|
407
494
|
|
|
408
495
|
async def _check_and_set_allowance(
|
|
409
496
|
self,
|
|
410
|
-
|
|
497
|
+
evm_account: EvmServerAccount,
|
|
411
498
|
token_address: str,
|
|
412
499
|
approval_address: str,
|
|
413
500
|
amount: str,
|
|
414
|
-
|
|
501
|
+
web3: Web3,
|
|
502
|
+
network_id: str,
|
|
503
|
+
wallet_address: str,
|
|
504
|
+
) -> str | None:
|
|
415
505
|
"""Check if token allowance is sufficient and set approval if needed."""
|
|
416
506
|
try:
|
|
417
507
|
# Normalize addresses
|
|
418
508
|
token_address = Web3.to_checksum_address(token_address)
|
|
419
509
|
approval_address = Web3.to_checksum_address(approval_address)
|
|
420
|
-
|
|
510
|
+
wallet_checksum = Web3.to_checksum_address(wallet_address)
|
|
511
|
+
|
|
512
|
+
contract = web3.eth.contract(address=token_address, abi=ERC20_ABI)
|
|
421
513
|
|
|
422
514
|
# Check current allowance
|
|
423
515
|
try:
|
|
424
|
-
current_allowance =
|
|
425
|
-
|
|
426
|
-
abi=ERC20_ABI,
|
|
427
|
-
function_name="allowance",
|
|
428
|
-
args=[wallet_address, approval_address],
|
|
516
|
+
current_allowance = await asyncio.to_thread(
|
|
517
|
+
contract.functions.allowance(wallet_checksum, approval_address).call
|
|
429
518
|
)
|
|
430
519
|
|
|
431
520
|
required_amount = int(amount)
|
|
@@ -447,20 +536,21 @@ class TokenExecute(LiFiBaseTool):
|
|
|
447
536
|
|
|
448
537
|
# Create approval transaction
|
|
449
538
|
approve_data = create_erc20_approve_data(approval_address, amount)
|
|
539
|
+
approval_request = TransactionRequestEIP1559(
|
|
540
|
+
to=token_address,
|
|
541
|
+
data=approve_data,
|
|
542
|
+
value=0,
|
|
543
|
+
)
|
|
450
544
|
|
|
451
545
|
# Send approval transaction
|
|
452
|
-
approval_tx_hash =
|
|
453
|
-
|
|
454
|
-
"to": token_address,
|
|
455
|
-
"data": approve_data,
|
|
456
|
-
"value": 0,
|
|
457
|
-
}
|
|
546
|
+
approval_tx_hash = await evm_account.send_transaction(
|
|
547
|
+
approval_request, network=network_id
|
|
458
548
|
)
|
|
459
549
|
|
|
460
550
|
# Wait for approval transaction confirmation
|
|
461
|
-
receipt =
|
|
551
|
+
receipt = await self._wait_for_receipt(web3, approval_tx_hash)
|
|
462
552
|
|
|
463
|
-
if not receipt or receipt.get("status")
|
|
553
|
+
if not receipt or receipt.get("status") != 1:
|
|
464
554
|
raise Exception(f"Approval transaction failed: {approval_tx_hash}")
|
|
465
555
|
|
|
466
556
|
return approval_tx_hash
|