Mint your DAT in Python

Prerequisites

  • Python 3.10+ and pip

  • A funded Pre‑Testnet wallet (for gas)

  • Credentials:

    • PRIVATE_KEY – your wallet private key (must start with 0x)

    • IPFS_JWT – Pinata (or compatible) IPFS JWT


1) Project setup

mkdir lazai-contribution-py
cd lazai-contribution-py

# (recommended) virtual environment
python3 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate

2) Install SDK & dependencies

python3 -m pip install -U alith requests rsa eth-account
# optional: if you want to load a .env file instead of exporting vars
# python3 -m pip install python-dotenv

3) Set environment variables

export PRIVATE_KEY=<your wallet private key>   # must start with 0x
export IPFS_JWT=<your pinata ipfs jwt>

If you prefer a .env file, install python-dotenv and load it at the top of the script.


4) Create

mint.py

Paste the script:

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
    # Optional fields that might not be present
    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()
                # Use the actual response structure instead of the broken model
                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()  # Use our custom implementation
    try:
        # 1. Prepare your privacy data and encrypt it
        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 the privacy data to IPFS and get the shared url
        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. Upload the privacy url to LazAI
        file_id = client.get_file_id_by_url(url)
        if file_id == 0:
            file_id = client.add_file(url)
        # 4. Request proof in the verified computing 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"Error: {e}")
    except Exception as e:
        raise e
    finally:
        await ipfs.close()


if __name__ == "__main__":
    asyncio.run(main())

5) Run

python mint.py

Expected output

Proof request sent successfully
Reward requested for file id <file_id>

Troubleshooting

  • eth_keys / signing errors → Ensure PRIVATE_KEY starts with 0x and you’re on Python 3.10+.

  • IPFS 401/403 → Check IPFS_JWT validity and pinning permissions.

  • Request/connection errors → Re-run after a minute; nodes may be busy. Confirm your RPC/Pre‑Testnet setup on the Quickstart page.

  • StorageError → Usually indicates bad token or network hiccup; retry the upload step.

Last updated