intentkit 0.6.11.dev7__py3-none-any.whl → 0.6.11.dev8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of intentkit might be problematic. Click here for more details.

intentkit/__init__.py CHANGED
@@ -3,7 +3,7 @@
3
3
  A powerful platform for building AI agents with blockchain and cryptocurrency capabilities.
4
4
  """
5
5
 
6
- __version__ = "0.6.11-dev7"
6
+ __version__ = "0.6.11-dev8"
7
7
  __author__ = "hyacinthus"
8
8
  __email__ = "hyacinthus@gmail.com"
9
9
 
@@ -52,6 +52,37 @@ class XmtpSwap(XmtpBaseTool):
52
52
  from_amount: str,
53
53
  slippage_bps: int = 100,
54
54
  ) -> Tuple[str, List[ChatMessageAttachment]]:
55
+ # Input validation
56
+ if (
57
+ not from_address
58
+ or not from_address.startswith("0x")
59
+ or len(from_address) != 42
60
+ ):
61
+ raise ValueError("from_address must be a valid Ethereum address")
62
+
63
+ if not from_token or not from_token.startswith("0x") or len(from_token) != 42:
64
+ raise ValueError("from_token must be a valid token contract address")
65
+
66
+ if not to_token or not to_token.startswith("0x") or len(to_token) != 42:
67
+ raise ValueError("to_token must be a valid token contract address")
68
+
69
+ if from_token.lower() == to_token.lower():
70
+ raise ValueError("from_token and to_token cannot be the same")
71
+
72
+ try:
73
+ amount_int = int(from_amount)
74
+ if amount_int <= 0:
75
+ raise ValueError("from_amount must be a positive integer")
76
+ except ValueError as e:
77
+ raise ValueError(f"from_amount must be a valid positive integer: {e}")
78
+
79
+ if (
80
+ not isinstance(slippage_bps, int)
81
+ or slippage_bps < 0
82
+ or slippage_bps > 10000
83
+ ):
84
+ raise ValueError("slippage_bps must be between 0 and 10000 (0% to 100%)")
85
+
55
86
  # Resolve agent context and target network
56
87
  context = self.get_context()
57
88
  agent = context.agent
@@ -98,88 +129,56 @@ class XmtpSwap(XmtpBaseTool):
98
129
  except Exception as e: # pragma: no cover - defensive
99
130
  raise ValueError(f"Failed to create swap quote via CDP: {e!s}")
100
131
 
101
- # Extract approval and swap calls if present (prefer QuoteSwapResult canonical fields)
132
+ # Extract transaction data from QuoteSwapResult
133
+ # CDP returns a single transaction object with all necessary data
102
134
  calls: list[dict] = []
103
135
 
104
- def to_xmtp_call(call_like, description: str) -> dict | None:
105
- if not call_like:
106
- return None
107
- # Attributes on QuoteSwapResult call-like objects
108
- to_value = getattr(call_like, "to", None) or getattr(
109
- call_like, "target", None
110
- )
111
- data_value = getattr(call_like, "data", None) or getattr(
112
- call_like, "calldata", None
113
- )
114
- value_value = getattr(call_like, "value", None)
115
- # Dict fallback
116
- if isinstance(call_like, dict):
117
- to_value = to_value or call_like.get("to") or call_like.get("target")
118
- data_value = (
119
- data_value or call_like.get("data") or call_like.get("calldata")
120
- )
121
- value_value = value_value or call_like.get("value")
122
- if not to_value or not data_value:
123
- return None
124
- value_hex = (
125
- value_value
126
- if isinstance(value_value, str) and value_value.startswith("0x")
127
- else (hex(int(value_value)) if value_value is not None else "0x0")
128
- )
129
- data_hex = (
130
- data_value if str(data_value).startswith("0x") else f"0x{data_value}"
131
- )
132
- return {
133
- "to": to_value,
134
- "value": value_hex,
135
- "data": data_hex,
136
- "metadata": {
137
- "description": description,
138
- "transactionType": "swap_step",
139
- "fromToken": from_token,
140
- "toToken": to_token,
141
- "amountIn": from_amount,
142
- "slippageBps": slippage_bps,
143
- },
144
- }
145
-
146
- # Heuristics for various response shapes
147
- approval = (
148
- getattr(quote, "approval", None)
149
- or getattr(quote, "approval_call_data", None)
150
- or (quote.get("approval") if isinstance(quote, dict) else None)
151
- or (quote.get("approval_call_data") if isinstance(quote, dict) else None)
152
- )
153
- approval_xmtp = to_xmtp_call(approval, "Approve token spending if required")
154
- if approval_xmtp:
155
- calls.append(approval_xmtp)
156
-
157
- swap_call = (
158
- getattr(quote, "swap", None)
159
- or getattr(quote, "swap_call_data", None)
160
- or (quote.get("swap") if isinstance(quote, dict) else None)
161
- or (quote.get("swap_call_data") if isinstance(quote, dict) else None)
162
- )
163
- swap_xmtp = to_xmtp_call(swap_call, "Execute token swap")
164
- if swap_xmtp:
165
- calls.append(swap_xmtp)
166
-
167
- if not calls:
168
- # As a final fallback, some responses may provide a generic 'calls' list
169
- raw_calls = getattr(quote, "calls", None) or (
170
- quote.get("calls") if isinstance(quote, dict) else None
171
- )
172
- if isinstance(raw_calls, list):
173
- for idx, c in enumerate(raw_calls):
174
- x = to_xmtp_call(c, f"Swap step {idx + 1}")
175
- if x:
176
- calls.append(x)
177
-
178
- if not calls:
136
+ # Validate that we have the required fields from CDP
137
+ if not hasattr(quote, "to") or not hasattr(quote, "data"):
179
138
  raise ValueError(
180
- "CDP swap quote did not return callable steps compatible with wallet_sendCalls"
139
+ "CDP swap quote missing required transaction fields (to, data)"
181
140
  )
182
141
 
142
+ # Format value field - ensure it's a hex string
143
+ value_hex = "0x0"
144
+ if hasattr(quote, "value") and quote.value:
145
+ if isinstance(quote.value, str) and quote.value.startswith("0x"):
146
+ value_hex = quote.value
147
+ else:
148
+ value_hex = hex(int(quote.value)) if quote.value != "0" else "0x0"
149
+
150
+ # Format data field - ensure it has 0x prefix
151
+ data_hex = quote.data if quote.data.startswith("0x") else f"0x{quote.data}"
152
+
153
+ # Get expected output amount for metadata
154
+ to_amount = getattr(quote, "to_amount", None) or "unknown"
155
+ min_to_amount = getattr(quote, "min_to_amount", None) or "unknown"
156
+
157
+ # Create the swap call following XMTP wallet_sendCalls format
158
+ swap_call = {
159
+ "to": quote.to,
160
+ "value": value_hex,
161
+ "data": data_hex,
162
+ "metadata": {
163
+ "description": f"Swap {from_amount} units of {from_token} for {to_token} (expected: {to_amount}, min: {min_to_amount})",
164
+ "transactionType": "swap",
165
+ "currency": from_token,
166
+ "amount": int(from_amount),
167
+ "toAddress": quote.to,
168
+ "fromToken": from_token,
169
+ "toToken": to_token,
170
+ "expectedOutput": to_amount,
171
+ "minimumOutput": min_to_amount,
172
+ "slippageBps": slippage_bps,
173
+ "network": agent.network_id,
174
+ },
175
+ }
176
+
177
+ calls.append(swap_call)
178
+
179
+ # Note: CDP's create_swap_quote already includes any necessary approvals
180
+ # in the single transaction if needed, or handles them via Permit2 signatures
181
+
183
182
  # Build XMTP wallet_sendCalls payload
184
183
  wallet_send_calls = {
185
184
  "version": "1.0",
@@ -195,10 +194,20 @@ class XmtpSwap(XmtpBaseTool):
195
194
  "json": wallet_send_calls,
196
195
  }
197
196
 
198
- # Human-friendly message
197
+ # Human-friendly message with more details
198
+ expected_output = getattr(quote, "to_amount", "unknown")
199
+ min_output = getattr(quote, "min_to_amount", "unknown")
200
+
199
201
  content_message = (
200
- f"I created a swap transaction request to exchange {from_amount} units of {from_token} "
201
- f"for {to_token} on {agent.network_id}. Review and sign to execute."
202
+ f"🔄 Swap transaction ready!\n\n"
203
+ f"**Details:**\n"
204
+ f"• From: {from_amount} units of {from_token}\n"
205
+ f"• To: {to_token}\n"
206
+ f"• Expected output: {expected_output} units\n"
207
+ f"• Minimum output: {min_output} units\n"
208
+ f"• Network: {agent.network_id}\n"
209
+ f"• Slippage: {slippage_bps / 100:.1f}%\n\n"
210
+ f"Please review the transaction details and sign to execute the swap."
202
211
  )
203
212
 
204
213
  return content_message, [attachment]
@@ -66,13 +66,20 @@ class XmtpTransfer(XmtpBaseTool):
66
66
  context = self.get_context()
67
67
  agent = context.agent
68
68
 
69
- # Check if agent is on base mainnet
70
- if agent.network_id != "base-mainnet" and agent.network_id != "base-sepolia":
69
+ # ChainId mapping for XMTP wallet_sendCalls
70
+ chain_id_hex_by_network = {
71
+ "base-mainnet": "0x2105", # 8453
72
+ "base-sepolia": "0x14A34", # 84532
73
+ }
74
+
75
+ if agent.network_id not in chain_id_hex_by_network:
71
76
  raise ValueError(
72
77
  f"XMTP transfer only supports base-mainnet or base-sepolia network. "
73
78
  f"Current agent network: {agent.network_id}"
74
79
  )
75
80
 
81
+ chain_id_hex = chain_id_hex_by_network[agent.network_id]
82
+
76
83
  # Calculate amount in smallest unit (wei for ETH, token units for ERC20)
77
84
  amount_int = int(float(amount) * (10**decimals))
78
85
 
@@ -127,7 +134,7 @@ class XmtpTransfer(XmtpBaseTool):
127
134
  wallet_send_calls = {
128
135
  "version": "1.0",
129
136
  "from": from_address,
130
- "chainId": "0x2105", # Base mainnet chain ID (8453 in hex)
137
+ "chainId": chain_id_hex,
131
138
  "calls": [
132
139
  {
133
140
  "to": transaction_to,
@@ -147,8 +154,12 @@ class XmtpTransfer(XmtpBaseTool):
147
154
 
148
155
  # Create user message
149
156
  content_message = (
150
- f"I have created a transaction request for transferring {amount} {currency} "
151
- f"to {to_address} on Base mainnet. "
157
+ f"💸 Transfer transaction ready!\n\n"
158
+ f"**Details:**\n"
159
+ f"• Amount: {amount} {currency}\n"
160
+ f"• To: {to_address}\n"
161
+ f"• Network: {agent.network_id}\n"
162
+ f"• Type: {'ERC20 Token' if token_contract_address else 'Native ETH'}\n\n"
152
163
  f"Please review the transaction details and sign to execute the transfer."
153
164
  )
154
165
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: intentkit
3
- Version: 0.6.11.dev7
3
+ Version: 0.6.11.dev8
4
4
  Summary: Intent-based AI Agent Platform - Core Package
5
5
  Project-URL: Homepage, https://github.com/crestal-network/intentkit
6
6
  Project-URL: Repository, https://github.com/crestal-network/intentkit
@@ -1,4 +1,4 @@
1
- intentkit/__init__.py,sha256=zSPkoV5ZbN43hygUd1OESGNoB0Almo18_29Olv5p7vw,384
1
+ intentkit/__init__.py,sha256=Q7VWjxlur_qiKhqxdojs0fc_I7bGzMUoKOL-TOGjWV4,384
2
2
  intentkit/abstracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  intentkit/abstracts/agent.py,sha256=108gb5W8Q1Sy4G55F2_ZFv2-_CnY76qrBtpIr0Oxxqk,1489
4
4
  intentkit/abstracts/api.py,sha256=ZUc24vaQvQVbbjznx7bV0lbbQxdQPfEV8ZxM2R6wZWo,166
@@ -392,8 +392,8 @@ intentkit/skills/xmtp/__init__.py,sha256=inpuVqA9i98g8VIqqfC28PbfveozSukbEHOLbOM
392
392
  intentkit/skills/xmtp/base.py,sha256=85ZEuNLJmI_NmBPkbvDXQrNvJNG8dp9MbcbQYQQ3QZ8,430
393
393
  intentkit/skills/xmtp/price.py,sha256=LqM3tWiW42bYIRqfvsZUvYpG5H5ife3WUhR-pxiS9I8,2648
394
394
  intentkit/skills/xmtp/schema.json,sha256=GFJKYPQVAcfiybL1uhAHANYeQUR0JWWxPgPhXW92N0s,3089
395
- intentkit/skills/xmtp/swap.py,sha256=f_cl8NMAWJ3q1t8_y1Bs8P6o78MzWb7Z85sIqLfAz-A,8082
396
- intentkit/skills/xmtp/transfer.py,sha256=hlkUu2UkTKx1Y7mUrBT4OjkWuzDK8DwfNpxYEwdOFhc,5860
395
+ intentkit/skills/xmtp/swap.py,sha256=8YEjfOTS-BtKKuXT1QLedBTM9h4QUF0rVYtLkC7WPG0,8412
396
+ intentkit/skills/xmtp/transfer.py,sha256=qmSIsSrWR-S5JFlBP4YjxudsWlKsCpp-JjDQjYUhdHg,6182
397
397
  intentkit/skills/xmtp/xmtp.png,sha256=vQzT-71zIb8aPodg-GkGSQbBnjGAPczWGm3es2ZkJe8,6681
398
398
  intentkit/utils/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
399
399
  intentkit/utils/chain.py,sha256=3GBHuAbXxQr_HlOvkbB2kruYSkweucfxI5u-swXzY40,15135
@@ -403,7 +403,7 @@ intentkit/utils/random.py,sha256=DymMxu9g0kuQLgJUqalvgksnIeLdS-v0aRk5nQU0mLI,452
403
403
  intentkit/utils/s3.py,sha256=9trQNkKQ5VgxWsewVsV8Y0q_pXzGRvsCYP8xauyUYkg,8549
404
404
  intentkit/utils/slack_alert.py,sha256=s7UpRgyzLW7Pbmt8cKzTJgMA9bm4EP-1rQ5KXayHu6E,2264
405
405
  intentkit/utils/tx.py,sha256=2yLLGuhvfBEY5n_GJ8wmIWLCzn0FsYKv5kRNzw_sLUI,1454
406
- intentkit-0.6.11.dev7.dist-info/METADATA,sha256=tu07mQ_LIrzS_KuValFiK-5GUB6zEeEO14O5t20v6Rw,6414
407
- intentkit-0.6.11.dev7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
408
- intentkit-0.6.11.dev7.dist-info/licenses/LICENSE,sha256=Bln6DhK-LtcO4aXy-PBcdZv2f24MlJFm_qn222biJtE,1071
409
- intentkit-0.6.11.dev7.dist-info/RECORD,,
406
+ intentkit-0.6.11.dev8.dist-info/METADATA,sha256=kzC29yoFVdS62rNNPYMlYUM96uCJWGeJ47kLIbqfN0A,6414
407
+ intentkit-0.6.11.dev8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
408
+ intentkit-0.6.11.dev8.dist-info/licenses/LICENSE,sha256=Bln6DhK-LtcO4aXy-PBcdZv2f24MlJFm_qn222biJtE,1071
409
+ intentkit-0.6.11.dev8.dist-info/RECORD,,