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\activate

Step 2. Install Dependencies

Install the LazAI SDK and required libraries.

python3 -m pip install -U alith requests rsa eth-account

If you prefer to load environment variables from a .env file instead of exporting them directly, install:

python3 -m pip install python-dotenv

Step 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.py

Expected 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:

  1. Set up a local LazAI development environment.

  2. Encrypt and upload data to IPFS.

  3. Register and anchor it on the LazAI Network.

  4. Generate verifiable proof and mint a DAT.

  5. 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