Python SDK for IntentLayer - handles intent recording and IPFS pinning
Project description
IntentLayer SDK for Python
A batteries-included client for the IntentLayer protocol: pin JSON payloads to IPFS, generate cryptographically-signed envelopes, and record intents on any EVM-compatible chain in a single call.
🚀 Key Benefits
-
Verifiable Audit Trail
Tie every action to a Decentralized Identifier (DID) and immutably log a hash on-chain. -
Built-in Incentives
Stake-and-slash model ensures compliance: honest actors earn yield; misbehavior burns stake. -
Zero Boilerplate
Onesend_intent()call handles IPFS pinning, envelope creation, signing, gas estimation, and transaction submission. -
Chain-Agnostic
Compatible with any HTTPS RPC endpoint and EVM-compatible network (Ethereum, zkSync, Polygon, etc.). -
Extensible Signing
Use raw private keys, hardware wallets, KMS, or your own signer implementation via a simpleSignerprotocol.
🔧 Installation
Install from PyPI:
pip install intentlayer-sdk
For development or latest changes:
git clone https://github.com/intentlayer/intentlayer-sdk.git
cd intentlayer-sdk
pip install -e .
🎯 Quickstart
import os
import time
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from intentlayer_sdk import (
IntentClient, create_envelope,
PinningError, EnvelopeError, TransactionError, NetworkError
)
# 1. Environment
PINNER_URL = os.getenv("PINNER_URL", "https://pin.example.com")
PRIVATE_KEY = os.getenv("PRIVATE_KEY") # never commit this!
# 2. Initialize client using network configuration
client = IntentClient.from_network(
network="zksync-era-sepolia", # Network from networks.json
pinner_url=PINNER_URL,
signer=PRIVATE_KEY, # Can be a private key string or a Signer instance
)
# Verify connected to the right chain
client.assert_chain_id()
# Query minimum stake from contract
min_stake = client.min_stake_wei
print(f"Minimum stake: {min_stake / 10**18} ETH")
# 3. Register a DID first (if not already registered)
did = "did:key:z6MkpzExampleDid"
try:
# Check if DID already exists
owner, active = client.resolve_did(did)
if owner == "0x0000000000000000000000000000000000000000":
# DID not registered yet - register it
print(f"Registering DID: {did}")
reg_receipt = client.register_did(did)
print(f"DID registered: {client.tx_url(reg_receipt['transactionHash'])}")
elif not active:
# DID exists but inactive
print(f"Reactivating DID: {did}")
client.register_did(did, force=True)
else:
print(f"DID already registered to {owner}")
except Exception as e:
print(f"Error checking/registering DID: {e}")
# 4. Create a signed envelope
prompt = "Translate 'hello' to French"
private_key = Ed25519PrivateKey.generate() # For envelope signing
# Create full envelope with signature
envelope = create_envelope(
prompt=prompt,
model_id="gpt-4o@2025-03-12",
tool_id="openai.chat",
did=did,
private_key=private_key,
stake_wei=min_stake,
timestamp_ms=int(time.time() * 1000)
)
# Get envelope hash for on-chain recording
envelope_hash = envelope.hex_hash()
# 5. Create payload with envelope
payload = {
"prompt": prompt,
"envelope": envelope.model_dump(),
"metadata": {
"user_id": "user123",
"session_id": "session456"
}
}
# 6. Record intent on-chain
try:
receipt = client.send_intent(envelope_hash=envelope_hash, payload_dict=payload)
tx_hash = receipt["transactionHash"]
print(f"✔️ TxHash: {tx_hash}")
print(f"✔️ Explorer: {client.tx_url(tx_hash)}")
except PinningError as e: print("IPFS error:", e)
except EnvelopeError as e: print("Envelope error:", e)
except NetworkError as e: print("Network error:", e)
except TransactionError as e: print("Tx failed:", e)
🔐 Security Best Practices
- Never hard-code private keys in source.
- Use environment variables, hardware wallets, or managed key services (AWS KMS, HashiCorp Vault).
- The SDK enforces HTTPS for RPC and pinner URLs in production (localhost/127.0.0.1 are exempt).
📚 High-Level API
IntentClient.from_network(...)
| Parameter | Type | Required | Description |
|---|---|---|---|
network |
str |
Yes | Network name from networks.json (e.g., "zksync-era-sepolia") |
pinner_url |
str |
Yes | IPFS pinner service URL |
signer |
Union[str, Signer] |
Yes | Private key string or Signer instance |
rpc_url |
str |
No | Override RPC URL from networks.json |
retry_count |
int (default=3) |
No | HTTP retry attempts |
timeout |
int (default=30) |
No | Request timeout in seconds |
logger |
logging.Logger |
No | Custom logger instance |
IntentClient(...) (Legacy constructor)
| Parameter | Type | Required | Description |
|---|---|---|---|
rpc_url |
str |
Yes | EVM RPC endpoint (must be https:// in prod) |
pinner_url |
str |
Yes | IPFS pinner service URL |
signer |
Signer |
Yes | Signer implementing .sign_transaction() |
recorder_address |
str |
Yes | Deployed IntentRecorder contract address |
did_registry_address |
str |
No | DIDRegistry contract address (for DID operations) |
retry_count |
int (default=3) |
No | HTTP retry attempts |
timeout |
int (default=30) |
No | Request timeout in seconds |
logger |
logging.Logger |
No | Custom logger instance |
Key Methods
create_envelope(...) → CallEnvelope
Creates a complete signed envelope for recording an intent.
from intentlayer_sdk import create_envelope
envelope = create_envelope(
prompt="What is the capital of France?",
model_id="gpt-4o@2025-03-12",
tool_id="openai.chat",
did="did:key:z6MkpzExampleDid",
private_key=private_key, # Ed25519PrivateKey instance
stake_wei=client.min_stake_wei
)
send_intent(...) → Dict[str, Any]
- Pins JSON to IPFS
- Builds & signs a
recordIntenttransaction - Sends it on-chain and waits for a receipt
register_did(did, ...) → Dict[str, Any]
Registers a DID with the DIDRegistry contract.
resolve_did(did) → Tuple[str, bool]
Resolves a DID to an address and active flag.
assert_chain_id()
Verifies the connected chain matches the expected chain ID.
tx_url(tx_hash) → str
Gets a block explorer URL for a transaction hash.
⚙️ Advanced Usage
Custom Signer
from web3 import Account
class VaultSigner:
def __init__(self, address, vault_client):
self.address = address
self.vault = vault_client
def sign_transaction(self, tx):
# fetch key from vault and sign
return self.vault.sign(tx)
client = IntentClient(
rpc_url = "…",
pinner_url = "…",
min_stake_wei = 10**16,
signer = VaultSigner("0xYourAddr", my_vault),
contract_address= "0x…"
)
🧪 Testing & Coverage
pytest --cov=intentlayer_sdk --cov-fail-under=80
We maintain ≥ 80% coverage to guarantee stability.
🤝 Contributing
- Fork the repo
- Create a feature branch (
git checkout -b feature/...) - Commit your changes
- Open a pull request
Please follow our Code of Conduct and Contribution Guidelines.
📝 License
This project is licensed under the MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file intentlayer_sdk-0.3.0.tar.gz.
File metadata
- Download URL: intentlayer_sdk-0.3.0.tar.gz
- Upload date:
- Size: 25.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.2 CPython/3.11.8 Darwin/24.4.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
490299702f8267f681084d36ee8314c931e5928c22d1d5897a3603d1aa747040
|
|
| MD5 |
4ca0ffdb8d456a4e3594296cfa6dec69
|
|
| BLAKE2b-256 |
8311def4ac92b9d8510927fbc55aafa7fd57ad1ba09919946866287e4e439be6
|
File details
Details for the file intentlayer_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: intentlayer_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 29.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.2 CPython/3.11.8 Darwin/24.4.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9bf70f61d590a473fbfaea6cea45529575d6ac7e5dbbbc9f1232ac104325577
|
|
| MD5 |
f0513aada6ec7f6253999fbe6cba4029
|
|
| BLAKE2b-256 |
26129f64ab3ca7febbd6d3143cb49a5b913a8463959818bb213d1d140efead1e
|