Mint your DAT in Python
This guide walks through the process of setting up your local environment, connecting your wallet, and minting your first Data Anchoring Token (DAT) using the LazAI Python SDK.
It assumes familiarity with Python, basic blockchain interactions, and access to the LazAI Pre-Testnet. For a guided walkthrough of the entire setup and minting process, watch the official tutorial: ➡️ https://youtu.be/YawyZ3aziRE?si=2i104Js04nxJ-oez
Prerequisites
Ensure the following tools and credentials are available before starting:
Requirement
Description
Python
Version 3.10 or later
pip
Latest package manager version
Wallet
Funded Pre-Testnet wallet for gas fees
Credentials
PRIVATE_KEY — your wallet private key (must start with 0x) IPFS_JWT — Pinata (or compatible) IPFS JWT token
Step 1. Project Setup
Create a new working directory and (optionally) set up a virtual environment.
mkdir lazai-contribution-py
cd lazai-contribution-py
# Optional: create a Python virtual environment
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activateStep 2. Install Dependencies
Install the LazAI SDK and required libraries.
python3 -m pip install -U alith requests rsa eth-accountIf you prefer to load environment variables from a .env file instead of exporting them directly, install:
python3 -m pip install python-dotenvStep 3. Configure Environment Variables
Set your credentials in the shell environment:
export PRIVATE_KEY=<your wallet private key> # must start with 0x
export IPFS_JWT=<your pinata ipfs jwt>If you are using a .env file, include:
from dotenv import load_dotenv
load_dotenv()at the top of your Python script.
Step 4. Create the Minting Script
Create a file named mint.py and paste the following code.
from alith.lazai import Client, ProofRequest
from alith.data import encrypt
from alith.data.storage import (
PinataIPFS,
UploadOptions,
GetShareLinkOptions,
StorageError,
)
from eth_account.messages import encode_defunct
from os import getenv
import asyncio
import requests
import rsa
import aiohttp
from pydantic import BaseModel
from typing import Optional
class ActualPinataUploadResponse(BaseModel):
id: str
name: str
cid: str
size: int
number_of_files: int
mime_type: str
created_at: str
updated_at: str
network: str
streamable: bool
accept_duplicates: Optional[bool] = None
is_duplicate: Optional[bool] = None
group_id: Optional[str] = None
class CustomPinataIPFS(PinataIPFS):
async def upload(self, opts: UploadOptions):
url = "https://uploads.pinata.cloud/v3/files"
form = aiohttp.FormData()
form.add_field("file", opts.data, filename=opts.name, content_type="text/plain")
form.add_field("network", "public")
headers = {"Authorization": f"Bearer {opts.token}"}
try:
async with self.client.post(url, data=form, headers=headers) as response:
if response.status != 200:
error_text = await response.text()
raise StorageError(f"Pinata IPFS API error: {error_text}")
data = await response.json()
pinata_response = ActualPinataUploadResponse(**data["data"])
from alith.data.storage import FileMetadata
return FileMetadata(
id=pinata_response.cid,
name=pinata_response.name,
size=pinata_response.size,
modified_time=pinata_response.updated_at,
)
except aiohttp.ClientError as e:
raise StorageError(f"Network error: {str(e)}") from e
async def main():
client = Client()
ipfs = CustomPinataIPFS()
try:
# 1. Prepare and encrypt data
data_file_name = "your_encrypted_data.txt"
privacy_data = "Your Privacy Data"
encryption_seed = "Sign to retrieve your encryption key"
message = encode_defunct(text=encryption_seed)
password = client.wallet.sign_message(message).signature.hex()
encrypted_data = encrypt(privacy_data.encode(), password)
# 2. Upload to IPFS
token = getenv("IPFS_JWT", "")
file_meta = await ipfs.upload(
UploadOptions(name=data_file_name, data=encrypted_data, token=token)
)
url = await ipfs.get_share_link(GetShareLinkOptions(token=token, id=file_meta.id))
# 3. Register file on LazAI
file_id = client.get_file_id_by_url(url)
if file_id == 0:
file_id = client.add_file(url)
# 4. Request proof from verified node
client.request_proof(file_id, 100)
job_id = client.file_job_ids(file_id)[-1]
job = client.get_job(job_id)
node_info = client.get_node(job[-1])
node_url: str = node_info[1]
pub_key = node_info[-1]
encryption_key = rsa.encrypt(
password.encode(),
rsa.PublicKey.load_pkcs1(pub_key.strip().encode(), format="PEM"),
).hex()
response = requests.post(
f"{node_url}/proof",
json=ProofRequest(
job_id=job_id,
file_id=file_id,
file_url=url,
encryption_key=encryption_key,
encryption_seed=encryption_seed,
proof_url=None,
).model_dump(),
)
if response.status_code == 200:
print("Proof request sent successfully.")
else:
print("Failed to send proof request:", response.json())
# 5. Request DAT reward
client.request_reward(file_id)
print("Reward requested for file id", file_id)
except StorageError as e:
print(f"Storage error: {e}")
except Exception as e:
raise e
finally:
await ipfs.close()
if __name__ == "__main__":
asyncio.run(main())Step 5. Run the Script
Execute the minting process.
python mint.pyExpected Output:
Proof request sent successfully
Reward requested for file id <file_id>Troubleshooting
Issue
Cause
Resolution
eth_keys or signing errors
Invalid private key format
Ensure PRIVATE_KEY starts with 0x and Python version ≥ 3.10
401 / 403 IPFS errors
Invalid or expired JWT
Verify your IPFS_JWT and permissions in Pinata
Request or connection failures
Node busy or network timeout
Wait a minute and retry; confirm your Pre-Testnet RPC configuration
StorageError
Invalid token or transient network issue
Retry the upload or reinitialize IPFS connection
Summary
This tutorial demonstrated how to:
Set up a local LazAI development environment.
Encrypt and upload data to IPFS.
Register and anchor it on the LazAI Network.
Generate verifiable proof and mint a DAT.
Request tokenized rewards on-chain.
Once this is running successfully, you can integrate the same workflow into your agent or service pipeline using the Alith SDK for automated data anchoring and reward management.
Last updated

