Skip to main content

Python SDK for IntentLayer - handles intent recording and IPFS pinning

Project description

PyPI version
Test Coverage
License: MIT

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
    One send_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 simple Signer protocol.


🔧 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 recordIntent transaction
  • 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

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/...)
  3. Commit your changes
  4. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

intentlayer_sdk-0.3.0.tar.gz (25.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

intentlayer_sdk-0.3.0-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

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

Hashes for intentlayer_sdk-0.3.0.tar.gz
Algorithm Hash digest
SHA256 490299702f8267f681084d36ee8314c931e5928c22d1d5897a3603d1aa747040
MD5 4ca0ffdb8d456a4e3594296cfa6dec69
BLAKE2b-256 8311def4ac92b9d8510927fbc55aafa7fd57ad1ba09919946866287e4e439be6

See more details on using hashes here.

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

Hashes for intentlayer_sdk-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c9bf70f61d590a473fbfaea6cea45529575d6ac7e5dbbbc9f1232ac104325577
MD5 f0513aada6ec7f6253999fbe6cba4029
BLAKE2b-256 26129f64ab3ca7febbd6d3143cb49a5b913a8463959818bb213d1d140efead1e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page