UNPKG

@basestamp/basestamp

Version:

TypeScript client library for Basestamp API with trustless Merkle proof verification

307 lines (211 loc) 7.7 kB
# Basestamp TypeScript Client A TypeScript client library for the Basestamp API with trustless Merkle proof verification. ## Installation ```bash npm install @basestamp/basestamp # or yarn add @basestamp/basestamp ``` ## Quick Start ```typescript import { BasestampClient, calculateSHA256 } from '@basestamp/basestamp'; // Initialize the client const client = new BasestampClient({ baseURL: 'https://api.basestamp.io' // Optional, this is the default }); // Hash your data const data = 'Hello, Basestamp!'; const hash = calculateSHA256(data); // Submit SHA256 hash for timestamping const stampId = await client.submitSHA256(hash); console.log('Stamp ID:', stampId); // Get the stamp (with optional waiting for Merkle proof) const stamp = await client.getStamp(stampId, { wait: true, timeout: 30 }); // Verify the timestamp with trustless verification const isValid = stamp.verify(hash); // throws descriptive errors if invalid console.log('Timestamp is valid:', isValid); ``` ## API Reference ### BasestampClient #### Constructor ```typescript new BasestampClient(options?: ClientOptions) ``` **Options:** - `baseURL?: string` - The base URL of the Basestamp API (default: 'https://api.basestamp.io') - `timeout?: number` - Request timeout in milliseconds (default: 30000) #### Methods ##### `submitSHA256(hash: string): Promise<string>` Submits a SHA256 hash for timestamping. **Parameters:** - `hash` - A SHA256 hash as a hex string **Returns:** Promise resolving to a stamp ID string ##### `getStamp(stampId: string, options?: StampOptions): Promise<Stamp>` Retrieves a stamp object with its Merkle proof. **Parameters:** - `stampId` - The unique identifier for the stamp - `options.wait` - Whether to wait for the proof if not immediately available (default: false) - `options.timeout` - Maximum time to wait in seconds (default: 30) **Returns:** Promise resolving to a Stamp object **Throws:** `BasestampError` if the proof is not available or times out ##### `info(): Promise<ServerInfo>` Gets information about the Basestamp server. **Returns:** Promise resolving to ServerInfo with server details ##### `health(): Promise<HealthResponse>` Checks the health status of the Basestamp server. **Returns:** Promise resolving to HealthResponse ##### `batchStats(): Promise<BatchStats>` Gets statistics about the batching process. **Returns:** Promise resolving to BatchStats ### Stamp Class #### `verify(original_hash: string): boolean` Verifies that the provided hash matches the stamp's Merkle proof. This is 100% local verification with no network calls. **Parameters:** - `original_hash` - The original hash value to verify **Returns:** `true` if the proof is valid **Throws:** Descriptive `BasestampError` explaining why verification failed: - Hash mismatch errors - Leaf hash verification failures - Merkle proof structure errors **Example:** ```typescript const stamp = await client.getStamp(stampId); try { const isValid = stamp.verify(originalHash); console.log('Verification successful!'); } catch (error) { console.log('Verification failed:', error.message); } ``` #### `getMerkleProof(): MerkleProof` Gets the underlying MerkleProof object for advanced use cases. **Returns:** MerkleProof instance **Throws:** `BasestampError` if no Merkle proof is available ### Deprecated Methods (for backward compatibility) ##### `get_merkle_proof(stampId: string, wait?: boolean, timeout?: number): Promise<MerkleProof>` **Deprecated:** Use `getStamp()` and call `stamp.getMerkleProof()` instead. ##### `verifyStamp(stampId: string, hashValue?: string): Promise<boolean>` **Deprecated:** Use `getStamp()` and call `stamp.verify()` instead. ### Utility Functions #### `calculateSHA256(data: Buffer | string): string` Calculates the SHA256 hash of the given data. **Parameters:** - `data` - Input data as Buffer or string **Returns:** SHA256 hash as a hex string #### `verifyMerkleProof(proof: MerkleProofData): boolean` Verifies a Merkle proof client-side (used internally). **Parameters:** - `proof` - A MerkleProofData object **Returns:** `true` if the proof is valid, `false` otherwise ## Types ### StampOptions ```typescript interface StampOptions { wait?: boolean; timeout?: number; } ``` ### Stamp ```typescript class Stamp { stamp_id: string; hash: string; original_hash: string; nonce: string; timestamp: string; status: string; message?: string; tx_id?: string; block_hash?: string; network?: string; chain_id?: string; verify(original_hash: string): boolean; getMerkleProof(): MerkleProof; } ``` ### MerkleProof ```typescript class MerkleProof { leaf_hash: string; leaf_index: number; siblings: string[]; directions: boolean[]; root_hash: string; nonce: string; original_hash: string; verify(hash_value: string): boolean; } ``` ## Error Handling The client throws `BasestampError` with descriptive messages: ```typescript import { BasestampError } from '@basestamp/basestamp'; try { const stamp = await client.getStamp(stampId); stamp.verify(hash); } catch (error) { if (error instanceof BasestampError) { console.log('Basestamp error:', error.message); // Examples: // "Hash mismatch: provided hash 'abc123' does not match stamp's original hash 'def456'" // "Leaf hash verification failed: expected 'xyz789' but merkle proof contains 'abc123'" // "Merkle proof verification failed: the proof structure does not produce the expected root hash" } else { console.log('Other error:', error); } } ``` ## Trustless Verification This client performs complete client-side verification of Merkle proofs, meaning you don't need to trust the Basestamp server. The verification process: 1. Retrieves the stamp data including the Merkle proof, nonce, and original hash 2. Calculates the expected leaf hash using `SHA256(nonce + original_hash)` 3. Verifies the calculated leaf hash matches the proof's leaf hash 4. Uses the proof to reconstruct the path from the leaf to the Merkle root 5. Verifies that the computed root matches the expected root hash 6. The root hash is anchored on the blockchain, providing cryptographic proof of inclusion The nonce-based approach prevents blockchain collision attacks while maintaining trustless verification. ## Examples ### File Timestamping ```typescript import { BasestampClient, calculateSHA256 } from '@basestamp/basestamp'; import { readFileSync } from 'fs'; const client = new BasestampClient(); // Read and hash a file const fileContent = readFileSync('document.pdf'); const fileHash = calculateSHA256(fileContent); // Submit for timestamping const stampId = await client.submitSHA256(fileHash); console.log(`File timestamped with ID: ${stampId}`); // Get the stamp (wait up to 30 seconds if needed) const stamp = await client.getStamp(stampId, { wait: true, timeout: 30 }); // Verify the timestamp try { stamp.verify(fileHash); console.log('Timestamp verification: VALID'); } catch (error) { console.log('Timestamp verification: INVALID -', error.message); } ``` ### Batch Processing ```typescript const client = new BasestampClient(); // Check batch statistics const stats = await client.batchStats(); console.log(`Pending stamps: ${stats.pending_stamps}`); console.log(`Batch interval: ${stats.batch_interval}`); ``` ## Testing The library includes comprehensive unit tests covering all functionality: ```bash # Run all tests yarn test # Run tests in watch mode yarn test:watch # Run linting yarn lint # Run type checking yarn typecheck ``` All tests use mocked data and do not depend on live API calls, ensuring fast and reliable testing. ## License MIT