Eulonomys: Permanent Eulogies on the Autonomys Network

Eulonomys is a reference application that preserves eulogies permanently using Auto Drive storage. Every tribute created with Eulonomys is immutable, censorship-resistant, and independent of any company or server.

This walkthrough highlights a new Auto Drive capability: Pay with AI3. Users can now pay for permanent storage on the Autonomys DSN directly with AI3 tokens from their wallet. No subscriptions. No intermediaries. Your words, preserved forever.

The real purpose of this app is to show developers how to build on Autonomys. Every pattern is meant to be copied, extended, and improved.


Video walkthrough


Try it

🕊️ Live app: eulonomys.vercel.app


Source code

The full source is open and meant to be forked:

github.com/autonomys-community/eulonomys


Pay with AI3 — Code Walkthrough

The following snippets are taken directly from the Eulonomys repository and show how Pay with AI3 is integrated end-to-end.

Creating a payment intent

The server-side API route creates a payment intent, watches the on-chain transaction, and polls for completion — all through the @autonomys/auto-drive SDK:

// src/app/api/payment/route.ts
 
import { createAutoDriveApi } from "@autonomys/auto-drive";
import { NextRequest, NextResponse } from "next/server";
import { config } from "@/config/app";
 
function getApi() {
  return createAutoDriveApi({
    apiKey: config.autoDrive.apiKey,
    apiUrl: config.autoDrive.apiUrl,
  });
}
 
export async function POST(request: NextRequest) {
  const body = await request.json();
  const { action } = body;
 
  // Step 1: Create an intent (locks price for 10 minutes)
  if (action === "createIntent") {
    const { contentSizeBytes } = body;
    const intent = await getApi().createPaymentIntent(contentSizeBytes);
    return NextResponse.json(intent);
  }
 
  // Step 2: User has sent the on-chain tx — submit hash for watching
  if (action === "watch") {
    const { intentId, txHash } = body;
    await getApi().watchPaymentTransaction(intentId, txHash);
    return NextResponse.json({ success: true });
  }
 
  // Step 3: Wait for intent to complete (long-poll)
  if (action === "waitForCompletion") {
    const { intentId } = body;
    const status = await getApi().waitForPaymentCompletion(intentId, {
      pollIntervalMs: 3000,
      timeoutMs: 300000,
    });
    return NextResponse.json({ status });
  }
}

Uploading to Auto Drive after payment

Once credits land, the app uploads the eulogy content using the SDK. The SdkAutoDriveClient wraps the SDK and provides a clean interface for the rest of the app:

// src/services/autoDrive.ts
 
import { createAutoDriveApi } from "@autonomys/auto-drive";
import { config } from "@/config/app";
 
export class SdkAutoDriveClient {
  private api: ReturnType<typeof createAutoDriveApi>;
 
  constructor() {
    this.api = createAutoDriveApi({
      provider: "apikey",
      apiKey: config.autoDrive.apiKey,
      apiUrl: config.autoDrive.apiUrl,
    });
  }
 
  async uploadFile(buffer: Buffer, filename: string) {
    const cid = await this.api.uploadFileFromBuffer(buffer, filename, {
      compression: true,
    });
    return { cid };
  }
 
  async uploadJson(data: Record<string, unknown>, filename: string) {
    const cid = await this.api.uploadObjectAsJSON(data, filename, {
      compression: true,
    });
    return { cid };
  }
}

App configuration

Minimal configuration is required — an API key and the network endpoints:

// src/config/app.ts
 
export const config = {
  autoDrive: {
    gatewayUrl:
      process.env.NEXT_PUBLIC_AUTO_DRIVE_GATEWAY_URL ||
      "https://gateway.autonomys.xyz/file",
    apiUrl:
      process.env.AUTO_DRIVE_API_URL ||
      "https://mainnet.auto-drive.autonomys.xyz/api",
    apiKey: process.env.AUTO_DRIVE_API_KEY || "",
  },
  payment: {
    pollIntervalMs: 3000,
    pollTimeoutMs: 300000,
  },
} as const;

Further reading