agent0-sdk 0.31__tar.gz → 1.0.1__tar.gz
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.
- agent0_sdk-1.0.1/MANIFEST.in +10 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/PKG-INFO +22 -14
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/README.md +20 -12
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/__init__.py +1 -1
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/agent.py +172 -30
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/contracts.py +93 -58
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/feedback_manager.py +90 -161
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/indexer.py +54 -26
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/models.py +6 -19
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/oasf_validator.py +1 -1
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/sdk.py +31 -16
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/subgraph_client.py +34 -15
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/web3_client.py +184 -17
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/PKG-INFO +22 -14
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/SOURCES.txt +2 -15
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/pyproject.toml +2 -2
- agent0_sdk-0.31/tests/__init__.py +0 -1
- agent0_sdk-0.31/tests/config.py +0 -46
- agent0_sdk-0.31/tests/conftest.py +0 -22
- agent0_sdk-0.31/tests/discover_test_data.py +0 -445
- agent0_sdk-0.31/tests/test_feedback.py +0 -417
- agent0_sdk-0.31/tests/test_models.py +0 -224
- agent0_sdk-0.31/tests/test_multi_chain.py +0 -588
- agent0_sdk-0.31/tests/test_oasf_management.py +0 -404
- agent0_sdk-0.31/tests/test_real_public_servers.py +0 -103
- agent0_sdk-0.31/tests/test_registration.py +0 -267
- agent0_sdk-0.31/tests/test_registrationIpfs.py +0 -227
- agent0_sdk-0.31/tests/test_sdk.py +0 -240
- agent0_sdk-0.31/tests/test_search.py +0 -415
- agent0_sdk-0.31/tests/test_transfer.py +0 -255
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/LICENSE +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/endpoint_crawler.py +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/ipfs_client.py +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/taxonomies/all_domains.json +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/taxonomies/all_skills.json +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/dependency_links.txt +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/requires.txt +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/top_level.txt +0 -0
- {agent0_sdk-0.31 → agent0_sdk-1.0.1}/setup.cfg +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent0-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Python SDK for agent portability, discovery and trust based on ERC-8004
|
|
5
|
-
Author-email: Marco De Rossi <marco
|
|
5
|
+
Author-email: Marco De Rossi <marco@ag0.xyz>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
8
|
Copyright (c) 2025 Marco De Rossi
|
|
@@ -76,7 +76,7 @@ Agent0 is the SDK for agentic economies. It enables agents to register, advertis
|
|
|
76
76
|
|
|
77
77
|
## What Does Agent0 SDK Do?
|
|
78
78
|
|
|
79
|
-
Agent0 SDK
|
|
79
|
+
Agent0 SDK enables you to:
|
|
80
80
|
|
|
81
81
|
- **Create and manage agent identities** - Register your AI agent on-chain with a unique identity, configure presentation fields (name, description, image), set wallet addresses, and manage trust models with x402 support
|
|
82
82
|
- **Advertise agent capabilities** - Publish MCP and A2A endpoints, with automated extraction of MCP tools and A2A skills from endpoints
|
|
@@ -86,11 +86,7 @@ Agent0 SDK v0.31 enables you to:
|
|
|
86
86
|
- **Cross-chain registration** - One-line registration with IPFS nodes, Pinata, Filecoin, or HTTP URIs
|
|
87
87
|
- **Public indexing** - Subgraph indexing both on-chain and IPFS data for fast search and retrieval
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Agent0 SDK v0.31 is in **alpha** with bugs and is not production ready. We're actively testing and improving it.
|
|
92
|
-
|
|
93
|
-
**Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco.derossi@consensys.net
|
|
89
|
+
**Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco@ag0.xyz
|
|
94
90
|
|
|
95
91
|
## Installation
|
|
96
92
|
|
|
@@ -152,12 +148,10 @@ agent.setENS("myagent.eth")
|
|
|
152
148
|
|
|
153
149
|
# Add OASF skills and domains (standardized taxonomies)
|
|
154
150
|
agent.addSkill("data_engineering/data_transformation_pipeline", validate_oasf=True)
|
|
155
|
-
agent.addSkill("natural_language_processing/summarization", validate_oasf=True)
|
|
151
|
+
agent.addSkill("natural_language_processing/natural_language_generation/summarization", validate_oasf=True)
|
|
156
152
|
agent.addDomain("finance_and_business/investment_services", validate_oasf=True)
|
|
157
|
-
agent.addDomain("technology/data_science", validate_oasf=True)
|
|
153
|
+
agent.addDomain("technology/data_science/data_science", validate_oasf=True)
|
|
158
154
|
|
|
159
|
-
# Configure wallet and trust
|
|
160
|
-
agent.setAgentWallet("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", chainId=11155111)
|
|
161
155
|
agent.setTrust(reputation=True, cryptoEconomic=True)
|
|
162
156
|
|
|
163
157
|
# Add metadata and set status
|
|
@@ -168,6 +162,16 @@ agent.setActive(True)
|
|
|
168
162
|
agent.registerIPFS()
|
|
169
163
|
print(f"Agent registered: {agent.agentId}") # e.g., "11155111:123"
|
|
170
164
|
print(f"Agent URI: {agent.agentURI}") # e.g., "ipfs://Qm..."
|
|
165
|
+
|
|
166
|
+
# (Optional) Change the agent wallet after registration
|
|
167
|
+
# - On mint/registration, `agentWallet` defaults to the current owner address.
|
|
168
|
+
# - Call this only if you want a DIFFERENT wallet (or after a transfer, since the wallet resets to zero).
|
|
169
|
+
# - Transaction is sent by the SDK signer (agent owner), but the signature must be produced by the NEW wallet.
|
|
170
|
+
agent.setAgentWallet(
|
|
171
|
+
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
|
172
|
+
chainId=11155111,
|
|
173
|
+
new_wallet_signer=os.getenv("NEW_WALLET_PRIVATE_KEY"),
|
|
174
|
+
)
|
|
171
175
|
```
|
|
172
176
|
|
|
173
177
|
### 3. Load and Edit Agent
|
|
@@ -213,7 +217,8 @@ agent_summary = sdk.getAgent("11155111:123")
|
|
|
213
217
|
feedback_file = sdk.prepareFeedback(
|
|
214
218
|
agentId="11155111:123",
|
|
215
219
|
score=85, # 0-100 (mandatory)
|
|
216
|
-
tags=["data_analyst", "finance"], # Optional
|
|
220
|
+
tags=["data_analyst", "finance"], # Optional: tags are now strings (not bytes32)
|
|
221
|
+
endpoint="https://example.com/endpoint", # Optional: endpoint URI associated with feedback
|
|
217
222
|
capability="tools", # Optional: MCP capability
|
|
218
223
|
name="code_generation", # Optional: MCP tool name
|
|
219
224
|
skill="python" # Optional: A2A skill
|
|
@@ -307,7 +312,7 @@ OASF skills and domains appear in your agent's registration file:
|
|
|
307
312
|
],
|
|
308
313
|
"domains": [
|
|
309
314
|
"finance_and_business/investment_services",
|
|
310
|
-
"technology/data_science"
|
|
315
|
+
"technology/data_science/data_science"
|
|
311
316
|
]
|
|
312
317
|
}
|
|
313
318
|
]
|
|
@@ -347,6 +352,9 @@ Complete working examples are available in the `tests/` directory:
|
|
|
347
352
|
- `test_feedback.py` - Complete feedback flow with IPFS storage
|
|
348
353
|
- `test_search.py` - Agent search and discovery
|
|
349
354
|
- `test_transfer.py` - Agent ownership transfer
|
|
355
|
+
- `test_oasf_management.py` - OASF skills/domains management (unit tests)
|
|
356
|
+
- `test_real_public_servers.py` - Endpoint crawler against real public MCP/A2A servers
|
|
357
|
+
- `test_multi_chain.py` - Multi-chain read-only operations (subgraph-based)
|
|
350
358
|
|
|
351
359
|
## Documentation
|
|
352
360
|
|
|
@@ -6,7 +6,7 @@ Agent0 is the SDK for agentic economies. It enables agents to register, advertis
|
|
|
6
6
|
|
|
7
7
|
## What Does Agent0 SDK Do?
|
|
8
8
|
|
|
9
|
-
Agent0 SDK
|
|
9
|
+
Agent0 SDK enables you to:
|
|
10
10
|
|
|
11
11
|
- **Create and manage agent identities** - Register your AI agent on-chain with a unique identity, configure presentation fields (name, description, image), set wallet addresses, and manage trust models with x402 support
|
|
12
12
|
- **Advertise agent capabilities** - Publish MCP and A2A endpoints, with automated extraction of MCP tools and A2A skills from endpoints
|
|
@@ -16,11 +16,7 @@ Agent0 SDK v0.31 enables you to:
|
|
|
16
16
|
- **Cross-chain registration** - One-line registration with IPFS nodes, Pinata, Filecoin, or HTTP URIs
|
|
17
17
|
- **Public indexing** - Subgraph indexing both on-chain and IPFS data for fast search and retrieval
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Agent0 SDK v0.31 is in **alpha** with bugs and is not production ready. We're actively testing and improving it.
|
|
22
|
-
|
|
23
|
-
**Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco.derossi@consensys.net
|
|
19
|
+
**Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco@ag0.xyz
|
|
24
20
|
|
|
25
21
|
## Installation
|
|
26
22
|
|
|
@@ -82,12 +78,10 @@ agent.setENS("myagent.eth")
|
|
|
82
78
|
|
|
83
79
|
# Add OASF skills and domains (standardized taxonomies)
|
|
84
80
|
agent.addSkill("data_engineering/data_transformation_pipeline", validate_oasf=True)
|
|
85
|
-
agent.addSkill("natural_language_processing/summarization", validate_oasf=True)
|
|
81
|
+
agent.addSkill("natural_language_processing/natural_language_generation/summarization", validate_oasf=True)
|
|
86
82
|
agent.addDomain("finance_and_business/investment_services", validate_oasf=True)
|
|
87
|
-
agent.addDomain("technology/data_science", validate_oasf=True)
|
|
83
|
+
agent.addDomain("technology/data_science/data_science", validate_oasf=True)
|
|
88
84
|
|
|
89
|
-
# Configure wallet and trust
|
|
90
|
-
agent.setAgentWallet("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", chainId=11155111)
|
|
91
85
|
agent.setTrust(reputation=True, cryptoEconomic=True)
|
|
92
86
|
|
|
93
87
|
# Add metadata and set status
|
|
@@ -98,6 +92,16 @@ agent.setActive(True)
|
|
|
98
92
|
agent.registerIPFS()
|
|
99
93
|
print(f"Agent registered: {agent.agentId}") # e.g., "11155111:123"
|
|
100
94
|
print(f"Agent URI: {agent.agentURI}") # e.g., "ipfs://Qm..."
|
|
95
|
+
|
|
96
|
+
# (Optional) Change the agent wallet after registration
|
|
97
|
+
# - On mint/registration, `agentWallet` defaults to the current owner address.
|
|
98
|
+
# - Call this only if you want a DIFFERENT wallet (or after a transfer, since the wallet resets to zero).
|
|
99
|
+
# - Transaction is sent by the SDK signer (agent owner), but the signature must be produced by the NEW wallet.
|
|
100
|
+
agent.setAgentWallet(
|
|
101
|
+
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
|
102
|
+
chainId=11155111,
|
|
103
|
+
new_wallet_signer=os.getenv("NEW_WALLET_PRIVATE_KEY"),
|
|
104
|
+
)
|
|
101
105
|
```
|
|
102
106
|
|
|
103
107
|
### 3. Load and Edit Agent
|
|
@@ -143,7 +147,8 @@ agent_summary = sdk.getAgent("11155111:123")
|
|
|
143
147
|
feedback_file = sdk.prepareFeedback(
|
|
144
148
|
agentId="11155111:123",
|
|
145
149
|
score=85, # 0-100 (mandatory)
|
|
146
|
-
tags=["data_analyst", "finance"], # Optional
|
|
150
|
+
tags=["data_analyst", "finance"], # Optional: tags are now strings (not bytes32)
|
|
151
|
+
endpoint="https://example.com/endpoint", # Optional: endpoint URI associated with feedback
|
|
147
152
|
capability="tools", # Optional: MCP capability
|
|
148
153
|
name="code_generation", # Optional: MCP tool name
|
|
149
154
|
skill="python" # Optional: A2A skill
|
|
@@ -237,7 +242,7 @@ OASF skills and domains appear in your agent's registration file:
|
|
|
237
242
|
],
|
|
238
243
|
"domains": [
|
|
239
244
|
"finance_and_business/investment_services",
|
|
240
|
-
"technology/data_science"
|
|
245
|
+
"technology/data_science/data_science"
|
|
241
246
|
]
|
|
242
247
|
}
|
|
243
248
|
]
|
|
@@ -277,6 +282,9 @@ Complete working examples are available in the `tests/` directory:
|
|
|
277
282
|
- `test_feedback.py` - Complete feedback flow with IPFS storage
|
|
278
283
|
- `test_search.py` - Agent search and discovery
|
|
279
284
|
- `test_transfer.py` - Agent ownership transfer
|
|
285
|
+
- `test_oasf_management.py` - OASF skills/domains management (unit tests)
|
|
286
|
+
- `test_real_public_servers.py` - Endpoint crawler against real public MCP/A2A servers
|
|
287
|
+
- `test_multi_chain.py` - Multi-chain read-only operations (subgraph-based)
|
|
280
288
|
|
|
281
289
|
## Documentation
|
|
282
290
|
|
|
@@ -176,16 +176,14 @@ class Agent:
|
|
|
176
176
|
return self.registration_file
|
|
177
177
|
|
|
178
178
|
def _collectMetadataForRegistration(self) -> List[Dict[str, Any]]:
|
|
179
|
-
"""Collect all metadata entries for registration.
|
|
179
|
+
"""Collect all metadata entries for registration.
|
|
180
|
+
|
|
181
|
+
Note: agentWallet is now a reserved metadata key and cannot be set via setMetadata().
|
|
182
|
+
It must be set separately using setAgentWallet() with EIP-712 signature verification.
|
|
183
|
+
"""
|
|
180
184
|
metadata_entries = []
|
|
181
185
|
|
|
182
|
-
#
|
|
183
|
-
if self.walletAddress:
|
|
184
|
-
addr_bytes = bytes.fromhex(self.walletAddress[2:]) # Remove '0x' prefix
|
|
185
|
-
metadata_entries.append({
|
|
186
|
-
"key": "agentWallet",
|
|
187
|
-
"value": addr_bytes
|
|
188
|
-
})
|
|
186
|
+
# Note: agentWallet is no longer set via metadata - it's now reserved and managed via setAgentWallet()
|
|
189
187
|
|
|
190
188
|
# Add ENS name metadata
|
|
191
189
|
if self.ensEndpoint:
|
|
@@ -339,7 +337,7 @@ class Agent:
|
|
|
339
337
|
Add a skill to the OASF endpoint.
|
|
340
338
|
|
|
341
339
|
Args:
|
|
342
|
-
slug: The skill slug to add (e.g., "natural_language_processing/summarization")
|
|
340
|
+
slug: The skill slug to add (e.g., "natural_language_processing/natural_language_generation/summarization")
|
|
343
341
|
validate_oasf: If True, validate the slug against the OASF taxonomy (default: False)
|
|
344
342
|
|
|
345
343
|
Returns:
|
|
@@ -492,20 +490,55 @@ class Agent:
|
|
|
492
490
|
self.registration_file.updatedAt = int(time.time())
|
|
493
491
|
return self
|
|
494
492
|
|
|
495
|
-
def setAgentWallet(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
493
|
+
def setAgentWallet(
|
|
494
|
+
self,
|
|
495
|
+
new_wallet: Address,
|
|
496
|
+
chainId: Optional[int] = None,
|
|
497
|
+
*,
|
|
498
|
+
new_wallet_signer: Optional[Union[str, Any]] = None,
|
|
499
|
+
deadline: Optional[int] = None,
|
|
500
|
+
signature: Optional[bytes] = None,
|
|
501
|
+
) -> 'Agent':
|
|
502
|
+
"""Set agent wallet address on-chain (ERC-8004 agentWallet).
|
|
503
|
+
|
|
504
|
+
This method is **on-chain only**. The `agentWallet` is a verified attribute and must be set via
|
|
505
|
+
the IdentityRegistry `setAgentWallet` function.
|
|
506
|
+
|
|
507
|
+
EOAs: provide `new_wallet_signer` (private key string or eth-account account) OR ensure the SDK
|
|
508
|
+
signer address matches `new_wallet` so the SDK can auto-sign.\n
|
|
509
|
+
Contract wallets (ERC-1271): provide `signature` bytes produced by the wallet’s signing mechanism.
|
|
510
|
+
The SDK will build the correct EIP-712 typed data internally, but cannot produce the wallet signature.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
new_wallet: New wallet address (must be controlled by the signer that produces the signature)
|
|
514
|
+
chainId: Optional local bookkeeping for registration file (walletChainId). Defaults to agent chain.
|
|
515
|
+
new_wallet_signer: EOA signer used to sign the EIP-712 message (private key string or eth-account account)
|
|
516
|
+
deadline: Signature deadline timestamp. Defaults to now+60s (must be <= now+5min per contract).
|
|
517
|
+
signature: Raw signature bytes (intended for ERC-1271 / external signing only)
|
|
518
|
+
"""
|
|
519
|
+
# Breaking/clean: this API is only meaningful for already-registered agents.
|
|
520
|
+
if not self.agentId:
|
|
521
|
+
raise ValueError(
|
|
522
|
+
"Cannot set agent wallet before the agent is registered on-chain. "
|
|
523
|
+
"Call agent.register(...) / agent.registerIPFS() first to obtain agentId."
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
addr = new_wallet
|
|
527
|
+
|
|
528
|
+
if not addr:
|
|
529
|
+
raise ValueError("Wallet address cannot be empty. Use a non-zero address.")
|
|
507
530
|
|
|
508
|
-
#
|
|
531
|
+
# Validate address format
|
|
532
|
+
if not addr.startswith("0x") or len(addr) != 42:
|
|
533
|
+
raise ValueError(f"Invalid Ethereum address format: {addr}. Must be 42 characters starting with '0x'")
|
|
534
|
+
|
|
535
|
+
# Validate hexadecimal characters
|
|
536
|
+
try:
|
|
537
|
+
int(addr[2:], 16)
|
|
538
|
+
except ValueError:
|
|
539
|
+
raise ValueError(f"Invalid hexadecimal characters in address: {addr}")
|
|
540
|
+
|
|
541
|
+
# Determine chain ID to use (local bookkeeping)
|
|
509
542
|
if chainId is None:
|
|
510
543
|
# Extract chain ID from agentId if available, otherwise use SDK's chain ID
|
|
511
544
|
if self.agentId and ":" in self.agentId:
|
|
@@ -516,14 +549,104 @@ class Agent:
|
|
|
516
549
|
else:
|
|
517
550
|
chainId = self.sdk.chainId # Use SDK's chain ID as fallback
|
|
518
551
|
|
|
519
|
-
#
|
|
520
|
-
if
|
|
521
|
-
|
|
552
|
+
# Parse agent ID
|
|
553
|
+
agent_id_int = int(self.agentId.split(":")[-1]) if ":" in self.agentId else int(self.agentId)
|
|
554
|
+
|
|
555
|
+
# Check if wallet is already set to this address (skip if same)
|
|
556
|
+
try:
|
|
557
|
+
current_wallet = self.sdk.web3_client.call_contract(
|
|
558
|
+
self.sdk.identity_registry,
|
|
559
|
+
"getAgentWallet",
|
|
560
|
+
agent_id_int
|
|
561
|
+
)
|
|
562
|
+
if current_wallet and current_wallet.lower() == addr.lower():
|
|
563
|
+
logger.debug(f"Agent wallet is already set to {addr}, skipping on-chain update")
|
|
564
|
+
# Still update local registration file
|
|
565
|
+
self.registration_file.walletAddress = addr
|
|
566
|
+
self.registration_file.walletChainId = chainId
|
|
567
|
+
self.registration_file.updatedAt = int(time.time())
|
|
568
|
+
return self
|
|
569
|
+
except Exception as e:
|
|
570
|
+
logger.debug(f"Could not check current agent wallet: {e}, proceeding with update")
|
|
571
|
+
|
|
572
|
+
# Set deadline (default to 60 seconds from now; contract max is now+5min)
|
|
573
|
+
if deadline is None:
|
|
574
|
+
deadline = int(time.time()) + 60
|
|
575
|
+
|
|
576
|
+
# Resolve typed data + signature
|
|
577
|
+
identity_registry_address = self.sdk.identity_registry.address
|
|
578
|
+
owner_address = self.sdk.web3_client.call_contract(self.sdk.identity_registry, "ownerOf", agent_id_int)
|
|
579
|
+
|
|
580
|
+
full_message = self.sdk.web3_client.build_agent_wallet_set_typed_data(
|
|
581
|
+
agent_id=agent_id_int,
|
|
582
|
+
new_wallet=addr,
|
|
583
|
+
owner=owner_address,
|
|
584
|
+
deadline=deadline,
|
|
585
|
+
verifying_contract=identity_registry_address,
|
|
586
|
+
chain_id=self.sdk.web3_client.chain_id,
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
if signature is None:
|
|
590
|
+
# EOA signing paths
|
|
591
|
+
if new_wallet_signer is not None:
|
|
592
|
+
# Validate signer address matches addr (fail fast)
|
|
593
|
+
try:
|
|
594
|
+
from eth_account import Account as _Account
|
|
595
|
+
if isinstance(new_wallet_signer, str):
|
|
596
|
+
signer_addr = _Account.from_key(new_wallet_signer).address
|
|
597
|
+
else:
|
|
598
|
+
signer_addr = getattr(new_wallet_signer, "address", None)
|
|
599
|
+
except Exception:
|
|
600
|
+
signer_addr = getattr(new_wallet_signer, "address", None)
|
|
601
|
+
|
|
602
|
+
if not signer_addr or signer_addr.lower() != addr.lower():
|
|
603
|
+
raise ValueError(
|
|
604
|
+
f"new_wallet_signer address ({signer_addr}) does not match new_wallet ({addr})."
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
signature = self.sdk.web3_client.sign_typed_data(full_message, new_wallet_signer) # type: ignore[arg-type]
|
|
608
|
+
else:
|
|
609
|
+
# Auto-sign only if SDK signer == new wallet
|
|
610
|
+
current_address = self.sdk.web3_client.account.address if self.sdk.web3_client.account else None
|
|
611
|
+
if current_address and current_address.lower() == addr.lower():
|
|
612
|
+
signature = self.sdk.web3_client.sign_typed_data(full_message, self.sdk.web3_client.account)
|
|
613
|
+
else:
|
|
614
|
+
raise ValueError(
|
|
615
|
+
f"New wallet must sign. Provide new_wallet_signer (EOA) or signature (ERC-1271/external). "
|
|
616
|
+
f"SDK signer is {current_address}, new_wallet is {addr}."
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
# Optional: verify recover matches addr for EOA signatures
|
|
620
|
+
recovered = self.sdk.web3_client.w3.eth.account.recover_message(
|
|
621
|
+
__import__("eth_account.messages").messages.encode_typed_data(full_message=full_message),
|
|
622
|
+
signature=signature,
|
|
623
|
+
)
|
|
624
|
+
if recovered.lower() != addr.lower():
|
|
625
|
+
raise ValueError(f"Signature verification failed: recovered {recovered} but expected {addr}")
|
|
626
|
+
|
|
627
|
+
# Call setAgentWallet on the contract
|
|
628
|
+
try:
|
|
629
|
+
txHash = self.sdk.web3_client.transact_contract(
|
|
630
|
+
self.sdk.identity_registry,
|
|
631
|
+
"setAgentWallet",
|
|
632
|
+
agent_id_int,
|
|
633
|
+
addr,
|
|
634
|
+
deadline,
|
|
635
|
+
signature
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
# Wait for transaction
|
|
639
|
+
receipt = self.sdk.web3_client.wait_for_transaction(txHash)
|
|
640
|
+
logger.debug(f"Agent wallet set on-chain: {txHash}")
|
|
641
|
+
|
|
642
|
+
except Exception as e:
|
|
643
|
+
raise ValueError(f"Failed to set agent wallet on-chain: {e}")
|
|
522
644
|
|
|
523
645
|
# Update local registration file
|
|
524
646
|
self.registration_file.walletAddress = addr
|
|
525
647
|
self.registration_file.walletChainId = chainId
|
|
526
648
|
self.registration_file.updatedAt = int(time.time())
|
|
649
|
+
self._last_registered_wallet = addr
|
|
527
650
|
|
|
528
651
|
return self
|
|
529
652
|
|
|
@@ -636,7 +759,7 @@ class Agent:
|
|
|
636
759
|
agentId = int(self.agentId.split(":")[-1])
|
|
637
760
|
txHash = self.sdk.web3_client.transact_contract(
|
|
638
761
|
self.sdk.identity_registry,
|
|
639
|
-
"
|
|
762
|
+
"setAgentURI",
|
|
640
763
|
agentId,
|
|
641
764
|
f"ipfs://{ipfsCid}"
|
|
642
765
|
)
|
|
@@ -673,7 +796,7 @@ class Agent:
|
|
|
673
796
|
agentId = int(self.agentId.split(":")[-1])
|
|
674
797
|
txHash = self.sdk.web3_client.transact_contract(
|
|
675
798
|
self.sdk.identity_registry,
|
|
676
|
-
"
|
|
799
|
+
"setAgentURI",
|
|
677
800
|
agentId,
|
|
678
801
|
f"ipfs://{ipfsCid}"
|
|
679
802
|
)
|
|
@@ -715,7 +838,7 @@ class Agent:
|
|
|
715
838
|
txHash = self.sdk.web3_client.transact_contract(
|
|
716
839
|
self.sdk.identity_registry,
|
|
717
840
|
"register",
|
|
718
|
-
"", # Empty
|
|
841
|
+
"", # Empty agentURI for now
|
|
719
842
|
metadata_entries
|
|
720
843
|
)
|
|
721
844
|
|
|
@@ -820,7 +943,7 @@ class Agent:
|
|
|
820
943
|
agentId = int(self.registration_file.agentId.split(":")[-1])
|
|
821
944
|
txHash = self.sdk.web3_client.transact_contract(
|
|
822
945
|
self.sdk.identity_registry,
|
|
823
|
-
"
|
|
946
|
+
"setAgentURI",
|
|
824
947
|
agentId,
|
|
825
948
|
agentURI
|
|
826
949
|
)
|
|
@@ -846,7 +969,12 @@ class Agent:
|
|
|
846
969
|
approve_operator: bool = False,
|
|
847
970
|
idem: Optional[IdemKey] = None,
|
|
848
971
|
) -> Dict[str, Any]:
|
|
849
|
-
"""Transfer agent ownership.
|
|
972
|
+
"""Transfer agent ownership.
|
|
973
|
+
|
|
974
|
+
Note: When an agent is transferred, the agentWallet is automatically reset
|
|
975
|
+
to the zero address on-chain. The new owner must call setAgentWallet() to
|
|
976
|
+
set a new wallet address with EIP-712 signature verification.
|
|
977
|
+
"""
|
|
850
978
|
if not self.registration_file.agentId:
|
|
851
979
|
raise ValueError("Agent must be registered before transferring")
|
|
852
980
|
|
|
@@ -863,6 +991,11 @@ class Agent:
|
|
|
863
991
|
|
|
864
992
|
receipt = self.sdk.web3_client.wait_for_transaction(txHash)
|
|
865
993
|
|
|
994
|
+
# Note: agentWallet will be reset to zero address by the contract
|
|
995
|
+
# Update local state to reflect this
|
|
996
|
+
self.registration_file.walletAddress = None
|
|
997
|
+
self._last_registered_wallet = None
|
|
998
|
+
|
|
866
999
|
return {
|
|
867
1000
|
"txHash": txHash,
|
|
868
1001
|
"agentId": self.registration_file.agentId,
|
|
@@ -907,6 +1040,10 @@ class Agent:
|
|
|
907
1040
|
|
|
908
1041
|
Only the current owner can transfer the agent.
|
|
909
1042
|
|
|
1043
|
+
Note: When an agent is transferred, the agentWallet is automatically reset
|
|
1044
|
+
to the zero address on-chain. The new owner must call setAgentWallet() to
|
|
1045
|
+
set a new wallet address with EIP-712 signature verification.
|
|
1046
|
+
|
|
910
1047
|
Args:
|
|
911
1048
|
newOwnerAddress: Ethereum address of the new owner
|
|
912
1049
|
|
|
@@ -964,6 +1101,11 @@ class Agent:
|
|
|
964
1101
|
|
|
965
1102
|
logger.debug(f"Agent {self.registration_file.agentId} successfully transferred to {checksum_address}")
|
|
966
1103
|
|
|
1104
|
+
# Note: agentWallet will be reset to zero address by the contract
|
|
1105
|
+
# Update local state to reflect this
|
|
1106
|
+
self.registration_file.walletAddress = None
|
|
1107
|
+
self._last_registered_wallet = None
|
|
1108
|
+
|
|
967
1109
|
return {"txHash": txHash, "from": currentOwner, "to": checksum_address, "agentId": self.registration_file.agentId}
|
|
968
1110
|
|
|
969
1111
|
def activate(self, idem: Optional[IdemKey] = None) -> RegistrationFile:
|