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.
Files changed (393) hide show
  1. intentkit/MANIFEST.in +14 -0
  2. intentkit/README.md +88 -0
  3. intentkit/__init__.py +6 -4
  4. intentkit/abstracts/agent.py +4 -5
  5. intentkit/abstracts/engine.py +5 -5
  6. intentkit/abstracts/graph.py +15 -8
  7. intentkit/abstracts/skill.py +6 -144
  8. intentkit/abstracts/twitter.py +4 -5
  9. intentkit/clients/__init__.py +9 -2
  10. intentkit/clients/cdp.py +129 -153
  11. intentkit/{utils → clients}/s3.py +109 -34
  12. intentkit/clients/twitter.py +83 -62
  13. intentkit/clients/web3.py +4 -7
  14. intentkit/config/config.py +123 -90
  15. intentkit/core/account_checking.py +802 -0
  16. intentkit/core/agent.py +313 -498
  17. intentkit/core/asset.py +267 -0
  18. intentkit/core/chat.py +5 -3
  19. intentkit/core/client.py +1 -1
  20. intentkit/core/credit.py +49 -41
  21. intentkit/core/draft.py +201 -0
  22. intentkit/core/draft_chat.py +118 -0
  23. intentkit/core/engine.py +378 -287
  24. intentkit/core/manager/__init__.py +25 -0
  25. intentkit/core/manager/engine.py +220 -0
  26. intentkit/core/manager/service.py +172 -0
  27. intentkit/core/manager/skills.py +178 -0
  28. intentkit/core/middleware.py +231 -0
  29. intentkit/core/prompt.py +74 -114
  30. intentkit/core/scheduler.py +143 -0
  31. intentkit/core/statistics.py +168 -0
  32. intentkit/models/agent.py +931 -518
  33. intentkit/models/agent_data.py +165 -106
  34. intentkit/models/agent_schema.json +38 -251
  35. intentkit/models/app_setting.py +15 -13
  36. intentkit/models/chat.py +86 -140
  37. intentkit/models/credit.py +182 -162
  38. intentkit/models/db.py +42 -23
  39. intentkit/models/db_mig.py +120 -3
  40. intentkit/models/draft.py +222 -0
  41. intentkit/models/llm.csv +31 -0
  42. intentkit/models/llm.py +262 -370
  43. intentkit/models/redis.py +6 -4
  44. intentkit/models/skill.py +222 -101
  45. intentkit/models/skills.csv +173 -0
  46. intentkit/models/team.py +189 -0
  47. intentkit/models/user.py +103 -31
  48. intentkit/skills/acolyt/__init__.py +2 -9
  49. intentkit/skills/acolyt/ask.py +3 -4
  50. intentkit/skills/acolyt/base.py +4 -9
  51. intentkit/skills/acolyt/schema.json +4 -3
  52. intentkit/skills/aixbt/__init__.py +2 -13
  53. intentkit/skills/aixbt/base.py +1 -7
  54. intentkit/skills/aixbt/projects.py +14 -15
  55. intentkit/skills/aixbt/schema.json +4 -4
  56. intentkit/skills/allora/__init__.py +2 -9
  57. intentkit/skills/allora/base.py +4 -9
  58. intentkit/skills/allora/price.py +3 -4
  59. intentkit/skills/allora/schema.json +3 -2
  60. intentkit/skills/base.py +241 -41
  61. intentkit/skills/basename/__init__.py +51 -0
  62. intentkit/skills/basename/base.py +11 -0
  63. intentkit/skills/basename/basename.svg +11 -0
  64. intentkit/skills/basename/schema.json +58 -0
  65. intentkit/skills/carv/__init__.py +115 -121
  66. intentkit/skills/carv/base.py +184 -185
  67. intentkit/skills/carv/fetch_news.py +3 -3
  68. intentkit/skills/carv/onchain_query.py +4 -4
  69. intentkit/skills/carv/schema.json +134 -137
  70. intentkit/skills/carv/token_info_and_price.py +6 -6
  71. intentkit/skills/casino/__init__.py +4 -15
  72. intentkit/skills/casino/base.py +1 -7
  73. intentkit/skills/casino/deck_draw.py +5 -8
  74. intentkit/skills/casino/deck_shuffle.py +6 -6
  75. intentkit/skills/casino/dice_roll.py +2 -4
  76. intentkit/skills/casino/schema.json +0 -1
  77. intentkit/skills/cdp/__init__.py +22 -84
  78. intentkit/skills/cdp/base.py +1 -7
  79. intentkit/skills/cdp/schema.json +11 -314
  80. intentkit/skills/chainlist/__init__.py +2 -7
  81. intentkit/skills/chainlist/base.py +1 -7
  82. intentkit/skills/chainlist/chain_lookup.py +18 -18
  83. intentkit/skills/chainlist/schema.json +3 -5
  84. intentkit/skills/common/__init__.py +2 -9
  85. intentkit/skills/common/base.py +1 -7
  86. intentkit/skills/common/current_time.py +1 -2
  87. intentkit/skills/common/schema.json +2 -2
  88. intentkit/skills/cookiefun/__init__.py +6 -9
  89. intentkit/skills/cookiefun/base.py +2 -7
  90. intentkit/skills/cookiefun/get_account_details.py +7 -7
  91. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  92. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  93. intentkit/skills/cookiefun/get_sectors.py +3 -3
  94. intentkit/skills/cookiefun/schema.json +1 -3
  95. intentkit/skills/cookiefun/search_accounts.py +9 -9
  96. intentkit/skills/cryptocompare/__init__.py +7 -24
  97. intentkit/skills/cryptocompare/api.py +2 -3
  98. intentkit/skills/cryptocompare/base.py +10 -24
  99. intentkit/skills/cryptocompare/fetch_news.py +4 -5
  100. intentkit/skills/cryptocompare/fetch_price.py +6 -7
  101. intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
  102. intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
  103. intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
  104. intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
  105. intentkit/skills/cryptocompare/schema.json +3 -3
  106. intentkit/skills/cryptopanic/__init__.py +7 -10
  107. intentkit/skills/cryptopanic/base.py +51 -55
  108. intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
  109. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
  110. intentkit/skills/cryptopanic/schema.json +105 -103
  111. intentkit/skills/dapplooker/__init__.py +2 -9
  112. intentkit/skills/dapplooker/base.py +4 -9
  113. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  114. intentkit/skills/dapplooker/schema.json +3 -5
  115. intentkit/skills/defillama/__init__.py +24 -74
  116. intentkit/skills/defillama/api.py +6 -9
  117. intentkit/skills/defillama/base.py +8 -19
  118. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
  119. intentkit/skills/defillama/coins/fetch_block.py +6 -8
  120. intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
  121. intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
  122. intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
  123. intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
  124. intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
  125. intentkit/skills/defillama/config/chains.py +1 -3
  126. intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
  127. intentkit/skills/defillama/schema.json +5 -1
  128. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
  129. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
  130. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
  131. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
  132. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  133. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
  134. intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
  135. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
  136. intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
  137. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
  138. intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
  139. intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
  140. intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
  141. intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
  142. intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
  143. intentkit/skills/defillama/yields/fetch_pools.py +26 -30
  144. intentkit/skills/dexscreener/__init__.py +97 -102
  145. intentkit/skills/dexscreener/base.py +125 -130
  146. intentkit/skills/dexscreener/get_pair_info.py +4 -5
  147. intentkit/skills/dexscreener/get_token_pairs.py +4 -5
  148. intentkit/skills/dexscreener/get_tokens_info.py +7 -8
  149. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  150. intentkit/skills/dexscreener/schema.json +91 -93
  151. intentkit/skills/dexscreener/search_token.py +182 -184
  152. intentkit/skills/dexscreener/utils.py +15 -14
  153. intentkit/skills/dune_analytics/__init__.py +7 -9
  154. intentkit/skills/dune_analytics/base.py +48 -52
  155. intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
  156. intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
  157. intentkit/skills/dune_analytics/schema.json +104 -99
  158. intentkit/skills/elfa/__init__.py +5 -18
  159. intentkit/skills/elfa/base.py +10 -14
  160. intentkit/skills/elfa/mention.py +19 -21
  161. intentkit/skills/elfa/schema.json +3 -2
  162. intentkit/skills/elfa/stats.py +4 -4
  163. intentkit/skills/elfa/tokens.py +12 -12
  164. intentkit/skills/elfa/utils.py +26 -28
  165. intentkit/skills/enso/__init__.py +11 -31
  166. intentkit/skills/enso/base.py +54 -35
  167. intentkit/skills/enso/best_yield.py +16 -24
  168. intentkit/skills/enso/networks.py +6 -11
  169. intentkit/skills/enso/prices.py +11 -13
  170. intentkit/skills/enso/route.py +34 -38
  171. intentkit/skills/enso/schema.json +3 -2
  172. intentkit/skills/enso/tokens.py +29 -38
  173. intentkit/skills/enso/wallet.py +76 -191
  174. intentkit/skills/erc20/__init__.py +50 -0
  175. intentkit/skills/erc20/base.py +11 -0
  176. intentkit/skills/erc20/erc20.svg +5 -0
  177. intentkit/skills/erc20/schema.json +74 -0
  178. intentkit/skills/erc721/__init__.py +53 -0
  179. intentkit/skills/erc721/base.py +11 -0
  180. intentkit/skills/erc721/erc721.svg +5 -0
  181. intentkit/skills/erc721/schema.json +90 -0
  182. intentkit/skills/firecrawl/__init__.py +5 -18
  183. intentkit/skills/firecrawl/base.py +4 -9
  184. intentkit/skills/firecrawl/clear.py +4 -8
  185. intentkit/skills/firecrawl/crawl.py +19 -19
  186. intentkit/skills/firecrawl/query.py +4 -3
  187. intentkit/skills/firecrawl/schema.json +2 -6
  188. intentkit/skills/firecrawl/scrape.py +17 -22
  189. intentkit/skills/firecrawl/utils.py +50 -42
  190. intentkit/skills/github/__init__.py +2 -7
  191. intentkit/skills/github/base.py +1 -7
  192. intentkit/skills/github/github_search.py +1 -2
  193. intentkit/skills/github/schema.json +3 -4
  194. intentkit/skills/heurist/__init__.py +8 -27
  195. intentkit/skills/heurist/base.py +4 -9
  196. intentkit/skills/heurist/image_generation_animagine_xl.py +13 -15
  197. intentkit/skills/heurist/image_generation_arthemy_comics.py +13 -15
  198. intentkit/skills/heurist/image_generation_arthemy_real.py +13 -15
  199. intentkit/skills/heurist/image_generation_braindance.py +13 -15
  200. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +13 -15
  201. intentkit/skills/heurist/image_generation_flux_1_dev.py +13 -15
  202. intentkit/skills/heurist/image_generation_sdxl.py +13 -15
  203. intentkit/skills/heurist/schema.json +2 -2
  204. intentkit/skills/http/__init__.py +4 -15
  205. intentkit/skills/http/base.py +1 -7
  206. intentkit/skills/http/get.py +21 -16
  207. intentkit/skills/http/post.py +23 -18
  208. intentkit/skills/http/put.py +23 -18
  209. intentkit/skills/http/schema.json +4 -5
  210. intentkit/skills/lifi/__init__.py +8 -13
  211. intentkit/skills/lifi/base.py +3 -9
  212. intentkit/skills/lifi/schema.json +17 -8
  213. intentkit/skills/lifi/token_execute.py +150 -60
  214. intentkit/skills/lifi/token_quote.py +8 -10
  215. intentkit/skills/lifi/utils.py +104 -51
  216. intentkit/skills/moralis/__init__.py +6 -10
  217. intentkit/skills/moralis/api.py +6 -7
  218. intentkit/skills/moralis/base.py +5 -10
  219. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  220. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  221. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  222. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  223. intentkit/skills/moralis/schema.json +7 -2
  224. intentkit/skills/morpho/__init__.py +52 -0
  225. intentkit/skills/morpho/base.py +11 -0
  226. intentkit/skills/morpho/morpho.svg +12 -0
  227. intentkit/skills/morpho/schema.json +73 -0
  228. intentkit/skills/nation/__init__.py +4 -9
  229. intentkit/skills/nation/base.py +5 -10
  230. intentkit/skills/nation/nft_check.py +3 -4
  231. intentkit/skills/nation/schema.json +4 -3
  232. intentkit/skills/onchain.py +30 -0
  233. intentkit/skills/openai/__init__.py +17 -18
  234. intentkit/skills/openai/base.py +10 -14
  235. intentkit/skills/openai/dalle_image_generation.py +4 -9
  236. intentkit/skills/openai/gpt_avatar_generator.py +102 -0
  237. intentkit/skills/openai/gpt_image_generation.py +5 -9
  238. intentkit/skills/openai/gpt_image_mini_generator.py +92 -0
  239. intentkit/skills/openai/gpt_image_to_image.py +5 -9
  240. intentkit/skills/openai/image_to_text.py +3 -7
  241. intentkit/skills/openai/schema.json +34 -3
  242. intentkit/skills/portfolio/__init__.py +11 -35
  243. intentkit/skills/portfolio/base.py +33 -19
  244. intentkit/skills/portfolio/schema.json +3 -5
  245. intentkit/skills/portfolio/token_balances.py +21 -21
  246. intentkit/skills/portfolio/wallet_approvals.py +17 -18
  247. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  248. intentkit/skills/portfolio/wallet_history.py +31 -31
  249. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  250. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  251. intentkit/skills/portfolio/wallet_profitability.py +18 -18
  252. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  253. intentkit/skills/portfolio/wallet_stats.py +3 -3
  254. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  255. intentkit/skills/pyth/__init__.py +50 -0
  256. intentkit/skills/pyth/base.py +11 -0
  257. intentkit/skills/pyth/pyth.svg +6 -0
  258. intentkit/skills/pyth/schema.json +75 -0
  259. intentkit/skills/skills.toml +36 -0
  260. intentkit/skills/slack/__init__.py +5 -17
  261. intentkit/skills/slack/base.py +3 -9
  262. intentkit/skills/slack/get_channel.py +8 -8
  263. intentkit/skills/slack/get_message.py +9 -9
  264. intentkit/skills/slack/schedule_message.py +5 -5
  265. intentkit/skills/slack/schema.json +2 -2
  266. intentkit/skills/slack/send_message.py +3 -5
  267. intentkit/skills/supabase/__init__.py +7 -23
  268. intentkit/skills/supabase/base.py +1 -7
  269. intentkit/skills/supabase/delete_data.py +4 -4
  270. intentkit/skills/supabase/fetch_data.py +12 -12
  271. intentkit/skills/supabase/insert_data.py +4 -4
  272. intentkit/skills/supabase/invoke_function.py +6 -6
  273. intentkit/skills/supabase/schema.json +2 -3
  274. intentkit/skills/supabase/update_data.py +6 -6
  275. intentkit/skills/supabase/upsert_data.py +4 -4
  276. intentkit/skills/superfluid/__init__.py +53 -0
  277. intentkit/skills/superfluid/base.py +11 -0
  278. intentkit/skills/superfluid/schema.json +89 -0
  279. intentkit/skills/superfluid/superfluid.svg +6 -0
  280. intentkit/skills/system/__init__.py +7 -24
  281. intentkit/skills/system/add_autonomous_task.py +10 -12
  282. intentkit/skills/system/delete_autonomous_task.py +2 -2
  283. intentkit/skills/system/edit_autonomous_task.py +14 -18
  284. intentkit/skills/system/list_autonomous_tasks.py +3 -5
  285. intentkit/skills/system/read_agent_api_key.py +6 -4
  286. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  287. intentkit/skills/system/schema.json +6 -8
  288. intentkit/skills/tavily/__init__.py +3 -12
  289. intentkit/skills/tavily/base.py +4 -9
  290. intentkit/skills/tavily/schema.json +3 -5
  291. intentkit/skills/tavily/tavily_extract.py +2 -4
  292. intentkit/skills/tavily/tavily_search.py +4 -6
  293. intentkit/skills/token/__init__.py +5 -10
  294. intentkit/skills/token/base.py +7 -11
  295. intentkit/skills/token/erc20_transfers.py +19 -19
  296. intentkit/skills/token/schema.json +3 -6
  297. intentkit/skills/token/token_analytics.py +3 -3
  298. intentkit/skills/token/token_price.py +13 -13
  299. intentkit/skills/token/token_search.py +9 -9
  300. intentkit/skills/twitter/__init__.py +11 -35
  301. intentkit/skills/twitter/base.py +22 -34
  302. intentkit/skills/twitter/follow_user.py +2 -6
  303. intentkit/skills/twitter/get_mentions.py +5 -12
  304. intentkit/skills/twitter/get_timeline.py +4 -12
  305. intentkit/skills/twitter/get_user_by_username.py +2 -6
  306. intentkit/skills/twitter/get_user_tweets.py +5 -13
  307. intentkit/skills/twitter/like_tweet.py +2 -6
  308. intentkit/skills/twitter/post_tweet.py +6 -9
  309. intentkit/skills/twitter/reply_tweet.py +6 -9
  310. intentkit/skills/twitter/retweet.py +2 -6
  311. intentkit/skills/twitter/schema.json +1 -0
  312. intentkit/skills/twitter/search_tweets.py +4 -12
  313. intentkit/skills/unrealspeech/__init__.py +2 -7
  314. intentkit/skills/unrealspeech/base.py +2 -8
  315. intentkit/skills/unrealspeech/schema.json +2 -5
  316. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  317. intentkit/skills/venice_audio/__init__.py +98 -106
  318. intentkit/skills/venice_audio/base.py +117 -121
  319. intentkit/skills/venice_audio/input.py +41 -41
  320. intentkit/skills/venice_audio/schema.json +151 -152
  321. intentkit/skills/venice_audio/venice_audio.py +38 -21
  322. intentkit/skills/venice_image/__init__.py +147 -154
  323. intentkit/skills/venice_image/api.py +138 -138
  324. intentkit/skills/venice_image/base.py +185 -192
  325. intentkit/skills/venice_image/config.py +33 -35
  326. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  327. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  328. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  329. intentkit/skills/venice_image/image_generation/image_generation_base.py +11 -10
  330. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  331. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  332. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  333. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  334. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  335. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  336. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  337. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  338. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  339. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  340. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  341. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  342. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  343. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  344. intentkit/skills/venice_image/schema.json +267 -267
  345. intentkit/skills/venice_image/utils.py +77 -78
  346. intentkit/skills/web_scraper/__init__.py +5 -18
  347. intentkit/skills/web_scraper/base.py +21 -7
  348. intentkit/skills/web_scraper/document_indexer.py +7 -6
  349. intentkit/skills/web_scraper/schema.json +2 -6
  350. intentkit/skills/web_scraper/scrape_and_index.py +15 -15
  351. intentkit/skills/web_scraper/utils.py +62 -63
  352. intentkit/skills/web_scraper/website_indexer.py +17 -19
  353. intentkit/skills/weth/__init__.py +49 -0
  354. intentkit/skills/weth/base.py +11 -0
  355. intentkit/skills/weth/schema.json +58 -0
  356. intentkit/skills/weth/weth.svg +6 -0
  357. intentkit/skills/wow/__init__.py +51 -0
  358. intentkit/skills/wow/base.py +11 -0
  359. intentkit/skills/wow/schema.json +89 -0
  360. intentkit/skills/wow/wow.svg +7 -0
  361. intentkit/skills/x402/__init__.py +58 -0
  362. intentkit/skills/x402/base.py +99 -0
  363. intentkit/skills/x402/http_request.py +117 -0
  364. intentkit/skills/x402/schema.json +40 -0
  365. intentkit/skills/x402/x402.webp +0 -0
  366. intentkit/skills/xmtp/__init__.py +4 -15
  367. intentkit/skills/xmtp/base.py +5 -5
  368. intentkit/skills/xmtp/price.py +7 -6
  369. intentkit/skills/xmtp/schema.json +69 -71
  370. intentkit/skills/xmtp/swap.py +6 -8
  371. intentkit/skills/xmtp/transfer.py +4 -6
  372. intentkit/utils/__init__.py +4 -0
  373. intentkit/utils/chain.py +198 -96
  374. intentkit/utils/ens.py +135 -0
  375. intentkit/utils/error.py +5 -2
  376. intentkit/utils/logging.py +9 -11
  377. intentkit/utils/schema.py +100 -0
  378. intentkit/utils/slack_alert.py +8 -8
  379. intentkit/utils/tx.py +16 -8
  380. intentkit/uv.lock +3377 -0
  381. {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/METADATA +13 -15
  382. intentkit-0.8.34.dev7.dist-info/RECORD +478 -0
  383. intentkit-0.8.34.dev7.dist-info/licenses/LICENSE +21 -0
  384. intentkit/core/node.py +0 -215
  385. intentkit/models/conversation.py +0 -286
  386. intentkit/models/generator.py +0 -347
  387. intentkit/skills/cdp/get_balance.py +0 -110
  388. intentkit/skills/cdp/swap.py +0 -121
  389. intentkit/skills/moralis/tests/__init__.py +0 -0
  390. intentkit/skills/moralis/tests/test_wallet.py +0 -511
  391. intentkit-0.7.5.dev3.dist-info/RECORD +0 -424
  392. {intentkit-0.7.5.dev3.dist-info/licenses → intentkit}/LICENSE +0 -0
  393. {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/WHEEL +0 -0
@@ -1,7 +1,8 @@
1
1
  import logging
2
- from typing import Any, Dict, Optional, Type, Union
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: Optional[Union[Dict[str, Any], str]] = Field(
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: Optional[Dict[str, str]] = Field(
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: Optional[Dict[str, Any]] = Field(
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: Optional[float] = Field(
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: Type[BaseModel] = HttpPutInput
55
+ args_schema: type[BaseModel] = HttpPutInput
55
56
 
56
57
  async def _arun(
57
58
  self,
58
59
  url: str,
59
- data: Optional[Union[Dict[str, Any], str]] = None,
60
- headers: Optional[Dict[str, str]] = None,
61
- params: Optional[Dict[str, Any]] = None,
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
- return f"Error: Request to {url} timed out after {timeout} seconds"
105
- except httpx.HTTPStatusError as e:
106
- return f"Error: HTTP {e.response.status_code} - {e.response.text}"
107
- except httpx.RequestError as e:
108
- return f"Error: Failed to connect to {url} - {str(e)}"
109
- except Exception as e:
110
- logger.error(f"Unexpected error in HTTP PUT request: {e}")
111
- return f"Error: Unexpected error occurred - {str(e)}"
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
- "HTTP",
9
- "Web",
10
- "API",
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 List, Optional, TypedDict
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: Optional[float] = 0.03
27
- allowed_chains: Optional[List[str]] = None
28
- max_execution_time: Optional[int] = 300
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
- store: SkillStoreABC,
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, store, config)
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,
@@ -1,20 +1,14 @@
1
- from typing import Type
2
-
3
1
  from pydantic import BaseModel, Field
4
2
 
5
- from intentkit.abstracts.skill import SkillStoreABC
6
- from intentkit.skills.base import IntentKitSkill
3
+ from intentkit.skills.onchain import IntentKitOnChainSkill
7
4
 
8
5
 
9
- class LiFiBaseTool(IntentKitSkill):
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: Type[BaseModel]
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": ["token_quote", "token_execute"],
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": ["ETH", "POL", "ARB", "OPT", "DAI"]
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": ["states", "enabled"],
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, Dict, List, Optional, Type
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 wallet provider.
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: Type[BaseModel] = TokenExecuteInput
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: Optional[List[str]] = None
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: Optional[List[str]] = None,
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__(skill_store=skill_store)
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: Dict[str, Any]) -> str:
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
- agent_id = context.agent_id
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 wallet provider
137
- cdp_wallet_provider = await self._get_cdp_wallet_provider(agent_id)
138
- if isinstance(cdp_wallet_provider, str): # Error message
139
- return cdp_wallet_provider
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
- # Get wallet address
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
- cdp_wallet_provider, quote_data
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
- cdp_wallet_provider, quote_data
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 _get_cdp_wallet_provider(self, agent_id: str):
184
- """Get CDP wallet provider with error handling."""
206
+ async def _get_evm_account(self) -> EvmServerAccount | str:
207
+ """Get CDP EVM account with error handling."""
185
208
  try:
186
- cdp_client = await get_cdp_client(agent_id, self.skill_store)
187
- if not cdp_client:
188
- return "CDP client not available. Please ensure your agent has CDP wallet configuration."
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
- cdp_wallet_provider = await cdp_client.get_wallet_provider()
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
- ) -> Dict[str, Any]:
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, wallet_provider, quote_data: Dict[str, Any]
253
- ) -> Optional[str]:
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
- wallet_provider, from_token_address, approval_address, from_amount
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, wallet_provider, quote_data: Dict[str, Any]
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(transaction_request)
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['value']}"
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 = wallet_provider.send_transaction(tx_params)
329
+ tx_hash = await evm_account.send_transaction(tx_request, network=network_id)
289
330
 
290
331
  # Wait for confirmation
291
- receipt = wallet_provider.wait_for_transaction_receipt(tx_hash)
292
- if not receipt or receipt.get("status") == 0:
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: Dict[str, Any],
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
- wallet_provider,
497
+ evm_account: EvmServerAccount,
411
498
  token_address: str,
412
499
  approval_address: str,
413
500
  amount: str,
414
- ) -> Optional[str]:
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
- wallet_address = wallet_provider.get_address()
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 = wallet_provider.read_contract(
425
- contract_address=token_address,
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 = wallet_provider.send_transaction(
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 = wallet_provider.wait_for_transaction_receipt(approval_tx_hash)
551
+ receipt = await self._wait_for_receipt(web3, approval_tx_hash)
462
552
 
463
- if not receipt or receipt.get("status") == 0:
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