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
| Operation | Base Cost | Variable Cost | Notes |
|---|
tlsn_request | 1 DEM | - | Initial request fee |
tlsn_store | 1 DEM | +1 DEM/KB | Storage fee based on proof size |
| Gas | Standard | - | 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
| Code | Description | Resolution |
|---|
TLSN_INVALID_URL | URL is not accessible or malformed | Verify URL format and accessibility |
TLSN_TIMEOUT | Notarization timed out | Retry or check target server |
TLSN_INSUFFICIENT_BALANCE | Not enough DEM for fees | Top up DEM balance |
TLSN_PROOF_TOO_LARGE | Proof exceeds maximum size | Reduce response size or use redactions |
TLSN_TOKEN_EXPIRED | Access token expired | Request will auto-retry |
TLSN_PROXY_UNAVAILABLE | No proxy available for domain | Wait 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
| Parameter | Type | Required | Description |
|---|
url | string | Yes | The target HTTPS URL to attest |
method | "GET" or "POST" | No | HTTP method (default: “GET”) |
headers | Record<string, string> | No | Custom headers to include |
body | string | No | Request body for POST requests |
commit | CommitRanges | No | Byte ranges to include in proof |
maxSentData | number | No | Max sent data in bytes (default: 16384) |
maxRecvData | number | No | Max 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
- Generate Transaction: Create the unsigned transaction
- Sign & Confirm: Send to wallet extension for user approval and signing
- 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);
}
}
);
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.