Skip to main content

TLSNotary API Reference

TLSNotaryService Class

The TLSNotaryService class manages attestation tokens and proof storage. It provides methods for both direct execution and wallet-confirmation flows.
import { TLSNotaryService } from '@kynesyslabs/demosdk/tlsnotary';

const service = new TLSNotaryService(demos);

Methods

requestAttestation()

Requests an attestation token for a target URL. Burns 1 DEM and returns a proxy URL.
const { proxyUrl, tokenId, expiresAt } = await service.requestAttestation({
    targetUrl: 'https://api.example.com/data'
});

requestAttestationWithConfirmation()

Same as requestAttestation() but allows user confirmation before broadcasting. Recommended for wallet extension apps.
const response = await service.requestAttestationWithConfirmation(
    { targetUrl: 'https://api.example.com/data' },
    {
        onConfirm: async (details) => {
            // Show transaction to user for approval
            // details.txHash, details.amount, details.description
            return await showUserConfirmDialog(details);
        }
    }
);

createTLSNotary()

Convenience method that handles the full setup: request token → get proxy → create TLSNotary instance → initialize WASM.
const { tlsn, tokenId, proxyUrl } = await service.createTLSNotary({
    targetUrl: 'https://api.example.com/data'
});

// Ready to attest immediately!
const result = await tlsn.attest({ url: 'https://api.example.com/data' });

createTLSNotaryWithConfirmation()

Same as createTLSNotary() but with user confirmation. Recommended for wallet extension apps.
const { tlsn, tokenId } = await service.createTLSNotaryWithConfirmation(
    { targetUrl: 'https://api.example.com/data' },
    {
        onConfirm: async (details) => {
            return await showUserConfirmDialog(details);
        }
    }
);

storeProof()

Stores an attestation proof on-chain or IPFS.
const { txHash, storageFee } = await service.storeProof(
    tokenId,
    JSON.stringify(presentation),
    { storage: 'onchain' } // or 'ipfs'
);

storeProofWithConfirmation()

Same as storeProof() but with user confirmation. Recommended for wallet extension apps.
const { txHash, storageFee } = await service.storeProofWithConfirmation(
    tokenId,
    JSON.stringify(presentation),
    { storage: 'onchain' },
    {
        onConfirm: async (details) => {
            return await showUserConfirmDialog(details);
        }
    }
);

calculateStorageFee()

Calculate the fee for storing a proof.
const fee = service.calculateStorageFee(5); // 6 DEM for 5KB proof (1 base + 5 per KB)

Response Types

AttestationTokenResponse

interface AttestationTokenResponse {
    proxyUrl: string;      // WebSocket proxy URL for attestation
    tokenId: string;       // Unique token ID
    expiresAt: number;     // Unix timestamp when token expires
    retriesLeft: number;   // Number of retry attempts remaining
}

StoreProofResponse

interface StoreProofResponse {
    txHash: string;          // Transaction hash
    storageFee: number;      // Total fee burned (in DEM)
    broadcastStatus: number; // HTTP status (200 = success)
    broadcastMessage?: string;
}

TransactionDetails (for confirmation callbacks)

interface TransactionDetails {
    transaction: any;      // The signed transaction object
    txHash: string;        // Transaction hash
    amount: number;        // Amount in DEM being burned
    description: string;   // Human-readable description
    targetUrl?: string;    // For attestation requests
    tokenId?: string;      // For store transactions
}

Native Transaction Types

TLSNotary uses two native transaction types:

tlsn_request

Requests a TLSNotary attestation. Creates an access token for the proxy.
// SDK handles this internally
const tx = await demos.createTransaction({
    type: "native",
    data: ["native", {
        nativeOperation: "tlsn_request",
        args: [targetUrl]
    }]
})
Cost: 1 DEM (burned as fee)

tlsn_store

Stores the proof on-chain after notarization completes.
// SDK handles this internally
const tx = await demos.createTransaction({
    type: "native",
    data: ["native", {
        nativeOperation: "tlsn_store",
        args: [proofId, proofData]
    }]
})
Cost: 1 DEM base + 1 DEM per KB (burned as storage fee)

Cost Structure

OperationBase CostVariable CostNotes
tlsn_request1 DEM-Initial request fee
tlsn_store1 DEM+1 DEM/KBStorage fee based on proof size
GasStandard-Network transaction gas
Example costs:
  • Small proof (1KB): 1 + 1 + 1 = 3 DEM + gas
  • Medium proof (5KB): 1 + 1 + 5 = 7 DEM + gas
  • Large proof (20KB): 1 + 1 + 20 = 22 DEM + gas

Error Codes

CodeDescriptionResolution
TLSN_INVALID_URLURL is not accessible or malformedVerify URL format and accessibility
TLSN_TIMEOUTNotarization timed outRetry or check target server
TLSN_INSUFFICIENT_BALANCENot enough DEM for feesTop up DEM balance
TLSN_PROOF_TOO_LARGEProof exceeds maximum sizeReduce response size or use redactions
TLSN_TOKEN_EXPIREDAccess token expiredRequest will auto-retry
TLSN_PROXY_UNAVAILABLENo proxy available for domainWait and retry

TLSNotary Class

The TLSNotary class performs the actual WASM-based attestation. Use it after getting a proxy URL from TLSNotaryService.
import { TLSNotary } from '@kynesyslabs/demosdk/tlsnotary';

const tlsn = new TLSNotary({
    notaryUrl: 'http://notary.example.com:7047',
    websocketProxyUrl: proxyUrl, // From TLSNotaryService
});

await tlsn.initialize(); // Load WASM

const result = await tlsn.attest({
    url: 'https://api.example.com/data',
    method: 'GET',
    headers: { 'Accept': 'application/json' },
});

attest() Parameters

ParameterTypeRequiredDescription
urlstringYesThe target HTTPS URL to attest
method"GET" or "POST"NoHTTP method (default: “GET”)
headersRecord<string, string>NoCustom headers to include
bodystringNoRequest body for POST requests
commitCommitRangesNoByte ranges to include in proof
maxSentDatanumberNoMax sent data in bytes (default: 16384)
maxRecvDatanumberNoMax receive data in bytes (default: 16384)

attest() Response

interface AttestResult {
    presentation: PresentationJSON;  // The proof data
    sent: string;                    // Sent request data
    recv: string;                    // Received response data
    time: number;                    // Attestation timestamp
    serverName: string;              // Server hostname
}

verify()

Verify an attestation proof:
const result = await tlsn.verify(presentationJSON);
// result: { time, serverName, sent, recv, notaryKey, verifyingKey }

Wallet Extension Integration

For production dApps, users connect via wallet extensions which handle key management. The SDK supports a 3-step flow for wallet extensions:

The 3-Step Wallet Flow

  1. Generate Transaction: Create the unsigned transaction
  2. Sign & Confirm: Send to wallet extension for user approval and signing
  3. Broadcast: Send the signed transaction to the network
The WithConfirmation methods implement this pattern:
// Example: Full attestation with wallet extension flow
const service = new TLSNotaryService(demos);

// Step 1 & 2: Generate and get user confirmation
const { tlsn, tokenId } = await service.createTLSNotaryWithConfirmation(
    { targetUrl: 'https://api.example.com/data' },
    {
        onConfirm: async (details) => {
            // In a dApp, this would show a modal to the user:
            // "Confirm burning 1 DEM for attestation?"
            // The wallet extension signs when user approves
            return await walletExtension.requestApproval(details.transaction);
        }
    }
);

// Step 3: Perform attestation (no blockchain interaction)
const result = await tlsn.attest({ url: 'https://api.example.com/data' });

// Step 1 & 2 again: Store proof with confirmation
await service.storeProofWithConfirmation(
    tokenId,
    JSON.stringify(result.presentation),
    { storage: 'onchain' },
    {
        onConfirm: async (details) => {
            // "Confirm burning 6 DEM to store proof?"
            return await walletExtension.requestApproval(details.transaction);
        }
    }
);

Custom Headers

const result = await tlsn.attest({
    url: "https://api.example.com/data",
    headers: {
        "Authorization": "Bearer your-token",
        "X-Custom-Header": "value"
    }
});

POST Requests

const result = await tlsn.attest({
    url: "https://api.example.com/submit",
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({ key: "value" })
});

Commit Ranges (Selective Disclosure)

Control which parts of the request/response to include in the proof:
const result = await tlsn.attest({
    url: "https://api.example.com/data",
    commit: {
        sent: [{ start: 0, end: 100 }],  // Include first 100 bytes of request
        recv: [{ start: 0, end: 500 }],  // Include first 500 bytes of response
    }
});
Larger commit ranges result in larger proofs, which increase storage costs. Only include the data you need to prove.