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 +1 -1
- intentkit/skills/xmtp/swap.py +89 -80
- intentkit/skills/xmtp/transfer.py +16 -5
- {intentkit-0.6.11.dev7.dist-info → intentkit-0.6.11.dev8.dist-info}/METADATA +1 -1
- {intentkit-0.6.11.dev7.dist-info → intentkit-0.6.11.dev8.dist-info}/RECORD +7 -7
- {intentkit-0.6.11.dev7.dist-info → intentkit-0.6.11.dev8.dist-info}/WHEEL +0 -0
- {intentkit-0.6.11.dev7.dist-info → intentkit-0.6.11.dev8.dist-info}/licenses/LICENSE +0 -0
intentkit/__init__.py
CHANGED
intentkit/skills/xmtp/swap.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
105
|
-
|
|
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
|
|
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"
|
|
201
|
-
f"
|
|
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
|
-
#
|
|
70
|
-
|
|
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":
|
|
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"
|
|
151
|
-
f"
|
|
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.
|
|
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=
|
|
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=
|
|
396
|
-
intentkit/skills/xmtp/transfer.py,sha256=
|
|
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.
|
|
407
|
-
intentkit-0.6.11.
|
|
408
|
-
intentkit-0.6.11.
|
|
409
|
-
intentkit-0.6.11.
|
|
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,,
|
|
File without changes
|
|
File without changes
|