|
1 | 1 | import json |
2 | 2 | import logging |
3 | 3 | from decimal import Decimal |
| 4 | +from typing import Any |
4 | 5 |
|
5 | 6 | from intentkit.config.config import config |
6 | 7 | from intentkit.models.agent import Agent |
@@ -279,3 +280,98 @@ async def process_agent_wallet( |
279 | 280 | ) |
280 | 281 |
|
281 | 282 | return agent_data |
| 283 | + |
| 284 | + |
| 285 | +def _resolve_safe_rpc_url(network_id: str, privy_wallet_data: dict[str, Any]) -> str: |
| 286 | + rpc_url = privy_wallet_data.get("rpc_url") |
| 287 | + if not rpc_url and config.chain_provider: |
| 288 | + try: |
| 289 | + chain_config = config.chain_provider.get_chain_config(network_id) |
| 290 | + rpc_url = chain_config.rpc_url |
| 291 | + except Exception as e: |
| 292 | + logger.warning(f"Failed to get RPC URL from chain provider: {e}") |
| 293 | + |
| 294 | + if not rpc_url: |
| 295 | + from intentkit.wallets.privy import CHAIN_CONFIGS |
| 296 | + |
| 297 | + chain_config = CHAIN_CONFIGS.get(network_id) |
| 298 | + if chain_config and chain_config.rpc_url: |
| 299 | + rpc_url = chain_config.rpc_url |
| 300 | + |
| 301 | + if not rpc_url: |
| 302 | + raise IntentKitAPIError( |
| 303 | + 500, |
| 304 | + "RpcUrlNotConfigured", |
| 305 | + f"RPC URL not configured for network {network_id}", |
| 306 | + ) |
| 307 | + |
| 308 | + return rpc_url |
| 309 | + |
| 310 | + |
| 311 | +async def set_agent_safe_token_spending_limit( |
| 312 | + agent_id: str, |
| 313 | + token_address: str, |
| 314 | + spending_limit: float, |
| 315 | +) -> dict[str, Any]: |
| 316 | + """Set token spending limit for a Safe agent using agent-level inputs only.""" |
| 317 | + from intentkit.core.agent.queries import get_agent |
| 318 | + from intentkit.wallets.privy import PrivyClient, set_safe_token_spending_limit |
| 319 | + |
| 320 | + agent = await get_agent(agent_id) |
| 321 | + if not agent: |
| 322 | + raise IntentKitAPIError( |
| 323 | + status_code=404, |
| 324 | + key="AgentNotFound", |
| 325 | + message=f"Agent with ID '{agent_id}' not found", |
| 326 | + ) |
| 327 | + if agent.wallet_provider != "safe": |
| 328 | + raise IntentKitAPIError( |
| 329 | + 400, |
| 330 | + "SafeWalletRequired", |
| 331 | + "Token spending limits can only be set for agents using wallet_provider='safe'.", |
| 332 | + ) |
| 333 | + |
| 334 | + agent_data = await AgentData.get(agent_id) |
| 335 | + if not agent_data.privy_wallet_data: |
| 336 | + raise IntentKitAPIError( |
| 337 | + 400, |
| 338 | + "PrivyWalletDataMissing", |
| 339 | + "Privy wallet data is missing for this Safe wallet agent.", |
| 340 | + ) |
| 341 | + |
| 342 | + try: |
| 343 | + privy_wallet_data = json.loads(agent_data.privy_wallet_data) |
| 344 | + except json.JSONDecodeError as e: |
| 345 | + raise IntentKitAPIError( |
| 346 | + 500, |
| 347 | + "PrivyWalletDataInvalid", |
| 348 | + "Privy wallet data is corrupted and cannot be parsed.", |
| 349 | + ) from e |
| 350 | + |
| 351 | + try: |
| 352 | + privy_wallet_id = privy_wallet_data["privy_wallet_id"] |
| 353 | + privy_wallet_address = privy_wallet_data["privy_wallet_address"] |
| 354 | + safe_address = privy_wallet_data["smart_wallet_address"] |
| 355 | + except KeyError as e: |
| 356 | + raise IntentKitAPIError( |
| 357 | + 500, |
| 358 | + "PrivyWalletDataIncomplete", |
| 359 | + "Privy wallet data is missing required fields.", |
| 360 | + ) from e |
| 361 | + |
| 362 | + network_id = ( |
| 363 | + privy_wallet_data.get("network_id") or agent.network_id or "base-mainnet" |
| 364 | + ) |
| 365 | + rpc_url = _resolve_safe_rpc_url(network_id, privy_wallet_data) |
| 366 | + |
| 367 | + privy_client = PrivyClient() |
| 368 | + return await set_safe_token_spending_limit( |
| 369 | + privy_client=privy_client, |
| 370 | + privy_wallet_id=privy_wallet_id, |
| 371 | + privy_wallet_address=privy_wallet_address, |
| 372 | + safe_address=safe_address, |
| 373 | + token_address=token_address, |
| 374 | + spending_limit=spending_limit, |
| 375 | + network_id=network_id, |
| 376 | + rpc_url=rpc_url, |
| 377 | + ) |
0 commit comments