Guide

Guide · Parte 2 di 6

Pubblica la tua prima PoE

La pubblicazione è la metà di Label 309 in cui un gateway serve davvero. La verifica è trustless e non richiede account; la pubblicazione invece mette una transazione sulla chain, e questo ha un costo, perciò la invii tramite un gateway Label 309 che costruisce la transazione, paga la fee e la addebita sul proprio modello di balance. L'SDK e la CLI sono indipendenti dal gateway: puntali a quello per cui possiedi una API key.

Ogni pubblicazione ha la stessa struttura in due passaggi: blocca un prezzo, poi invia. Il gateway calcola il prezzo del record da uno snapshot FX in tempo reale e restituisce un quote_id valido per 15 minuti; la chiamata di pubblicazione lo consuma in modo atomico insieme all'inserimento on-chain. Gli helper di alto livello calcolano l'hash del tuo contenuto e costruiscono al posto tuo il record in canonical-CBOR.

Con la CLI

Installa il binario cardanowall, poi punta submit a un file. Ne calcola l'hash, ancora il digest e stampa il risultato:

cardanowall submit \
  --file ./contract.pdf \
  --base-url https://your-gateway.example \
  --api-key "$CW_API_KEY"

--base-url e --api-key vengono letti anche dalle variabili CARDANOWALL_BASE_URL e CARDANOWALL_API_KEY, oppure da un profilo gateway salvato, così spariscono dal comando in CI. Se hai già il digest, ancoralo direttamente con --hash invece di --file; aggiungi --alg blake2b-256 per passare dal valore predefinito sha2-256, e --json per un riepilogo leggibile da una macchina:

cardanowall submit --hash 3b9f…c1a2 --json

Per firmare il record con la tua chiave di identità, passa il seed master a 32 byte tramite --seed-file o --seed-stdin (mai --seed nudo su argv: finirebbe nella cronologia della shell). Omettilo per pubblicare senza firma.

Con l'SDK TypeScript

Crea un client verso il tuo gateway, poi richiedi il preventivo e pubblica in un'unica chiamata helper. publishContent calcola l'hash dei byte, costruisce il record e lo invia:

import { Label309Client } from '@cardanowall/sdk-ts';

const client = new Label309Client({
  baseUrl: 'https://your-gateway.example',
  apiKey: process.env.CW_API_KEY,
});

const quote = await client.poe.quote({
  recordBytes: 256,
  recipientCount: 0,
  fileBytesTotal: 0,
});

const result = await client.poe.publishContent({
  content: fileBytes, // Uint8Array or a UTF-8 string
  quoteId: quote.quote_id,
  // idempotencyKey: crypto.randomUUID(), // safe to retry the same submit
  // signer is optional — omit to publish unsigned (profile=core)
});

console.log(result.id, result.tx_hash, result.status);
console.log(result.balance_after_usd_micros); // decimal string of USD micro-cents

result.status parte da submitting; tx_hash resta null finché il gateway non costruisce la transazione. Passa un idempotencyKey per rendere sicuri i tentativi ripetuti: un invio identico ripetuto restituisce il record originale (dedup_hit: true) senza addebitare una seconda volta. Per un digest precalcolato usa publishPrehashed; per una busta sigillata indirizzata a un destinatario usa publishSealed.

Con l'SDK Python

cardanowall-sdk rispecchia gli helper TypeScript metodo per metodo. Il client è un async context manager; le risposte tornano come semplici dizionari:

import asyncio
from cardanowall.client import Label309Client


async def main() -> None:
    async with Label309Client(
        base_url="https://your-gateway.example",
        api_key="<opaque-bearer>",
    ) as client:
        quote = await client.poe.quote(
            record_bytes=256, recipient_count=0, file_bytes_total=0
        )
        out = await client.poe.publish_content(
            content="hello world",  # str (UTF-8) or bytes
            quote_id=quote["quote_id"],
        )
        print(out["id"], out["tx_hash"], out["status"])


asyncio.run(main())

Con l'SDK Rust

Il crate cardanowall espone lo stesso client indipendente dal gateway. Le chiamate sono bloccanti, quindi non serve alcun runtime async; gli helper restituiscono risultati tipizzati:

use cardanowall::client::{
    Label309Client, Label309ClientConfig, PublishContentInput, QuoteInput,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Label309Client::new(Label309ClientConfig {
        base_url: Some("https://your-gateway.example".into()),
        api_key: std::env::var("CW_API_KEY").ok(),
    })?;

    let quote = client.poe().quote(&QuoteInput {
        record_bytes: 256,
        recipient_count: 0,
        file_bytes_total: 0,
    })?;

    let result = client.poe().publish_content(&PublishContentInput {
        content: file_bytes, // Vec<u8>
        quote_id: quote.quote_id,
        hash_alg: None, // defaults to sha2-256
        signer: None,   // omit to publish unsigned (profile = core)
        idempotency_key: None,
    })?;

    println!("{} {:?} {:?}", result.id, result.tx_hash, result.status);
    Ok(())
}

Per un digest precalcolato usa publish_prehashed; per una busta sigillata indirizzata a un destinatario usa publish_sealed.

La fee è del gateway, la prova è tua

Il gateway tramite cui pubblichi paga la fee Cardano e l'addebita sul proprio modello di balance, ma il record che ancora è semplice metadati Label 309 con label 309. Chiunque può verificarlo a partire dalla sola chain pubblica, senza account e senza riporre alcuna fiducia nel gateway. Per indirizzare invece un record a un destinatario, vedi costruire una PoE sigillata; per la struttura esatta on-chain, leggi il record.