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.2.1.tar.gz (20.4 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.2.1-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

Details for the file intentlayer_sdk-0.2.1.tar.gz.

File metadata

  • Download URL: intentlayer_sdk-0.2.1.tar.gz
  • Upload date:
  • Size: 20.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.2 CPython/3.11.12 Linux/6.11.0-1012-azure

File hashes

Hashes for intentlayer_sdk-0.2.1.tar.gz
Algorithm Hash digest
SHA256 b788ba44242dd3f8ebcddffbb460a191317b6b012201f18eafe968ed6f921281
MD5 405d43473eadec7ec62fb77b960d1cd7
BLAKE2b-256 ed2282b02bd8a43ac53ec708a732d4048ebb50a0368e4974cc716911b26ff4a0

See more details on using hashes here.

File details

Details for the file intentlayer_sdk-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: intentlayer_sdk-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 22.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.2 CPython/3.11.12 Linux/6.11.0-1012-azure

File hashes

Hashes for intentlayer_sdk-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 34ca04f00037c0b8a7b7a2b1b2769bb5a2df30647c9e39ccfa03048bf44ba0b8
MD5 712b84ed2a250aa0aea92fd755b68401
BLAKE2b-256 0ff49cde39427fe442081d60ed910327fac5dc4105a941c3552ab3c32fe544fe

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