Initial commit

This commit is contained in:
defiQUG
2026-01-01 08:04:06 -08:00
commit d0bc005be1
75 changed files with 15082 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
import { chain138 } from '@dbis-thirdweb/chain';
/**
* HTTP API client configuration
*/
export interface APIClientConfig {
/**
* Base URL for API requests
*/
baseURL: string;
/**
* API key (if required)
*/
apiKey?: string;
/**
* Request timeout in milliseconds
* @default 30000
*/
timeout?: number;
/**
* Number of retries for failed requests
* @default 3
*/
retries?: number;
/**
* Retry delay in milliseconds (exponential backoff base)
* @default 1000
*/
retryDelay?: number;
/**
* Chain ID (should be Chain 138)
*/
chainId: number;
}
/**
* Default configuration for Chain 138
*/
export const defaultConfig: APIClientConfig = {
baseURL: 'https://api.thirdweb.com',
timeout: 30000,
retries: 3,
retryDelay: 1000,
chainId: chain138.chainId,
};
/**
* Sleep utility for retry delays
*/
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* HTTP API client with retry logic and timeout handling
*/
export class APIClient {
private config: APIClientConfig;
constructor(config: Partial<APIClientConfig> = {}) {
this.config = { ...defaultConfig, ...config };
}
/**
* Make HTTP request with retries and timeout
*/
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${this.config.baseURL}${endpoint}`;
const timeout = this.config.timeout || 30000;
// Add API key to headers if provided
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(options.headers as Record<string, string>),
};
if (this.config.apiKey) {
headers['Authorization'] = `Bearer ${this.config.apiKey}`;
}
// Add chain ID to headers if needed
headers['x-chain-id'] = this.config.chainId.toString();
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
let lastError: Error | null = null;
const maxRetries = this.config.retries || 3;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, {
...options,
headers,
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data as T;
} catch (error) {
clearTimeout(timeoutId);
lastError = error as Error;
// Don't retry on abort (timeout)
if (error instanceof Error && error.name === 'AbortError') {
throw new Error(`Request timeout after ${timeout}ms`);
}
// Don't retry on last attempt
if (attempt < maxRetries) {
const delay = this.config.retryDelay! * Math.pow(2, attempt); // Exponential backoff
await sleep(delay);
continue;
}
}
}
throw lastError || new Error('Request failed after retries');
}
/**
* GET request
*/
async get<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'GET' });
}
/**
* POST request
*/
async post<T>(endpoint: string, body?: unknown): Promise<T> {
return this.request<T>(endpoint, {
method: 'POST',
body: body ? JSON.stringify(body) : undefined,
});
}
/**
* PUT request
*/
async put<T>(endpoint: string, body?: unknown): Promise<T> {
return this.request<T>(endpoint, {
method: 'PUT',
body: body ? JSON.stringify(body) : undefined,
});
}
/**
* DELETE request
*/
async delete<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'DELETE' });
}
}
/**
* Create API client for Chain 138
*/
export function createAPIClient(config?: Partial<APIClientConfig>): APIClient {
return new APIClient(config);
}

View File

@@ -0,0 +1,119 @@
import { APIClient, createAPIClient } from './client';
/**
* Chain metadata response
*/
export interface ChainMetadata {
chainId: number;
name: string;
nativeCurrency: {
name: string;
symbol: string;
decimals: number;
};
rpc: string[];
explorers?: Array<{
name: string;
url: string;
}>;
}
/**
* Transaction receipt response
*/
export interface TransactionReceipt {
blockHash: string;
blockNumber: number;
contractAddress: string | null;
cumulativeGasUsed: string;
effectiveGasPrice: string;
from: string;
gasUsed: string;
logs: Array<{
address: string;
topics: string[];
data: string;
}>;
logsBloom: string;
status: number;
to: string | null;
transactionHash: string;
transactionIndex: number;
}
/**
* Block response
*/
export interface BlockResponse {
number: number;
hash: string;
parentHash: string;
timestamp: number;
transactions: string[];
}
/**
* Chain 138 API endpoints wrapper
*/
export class Chain138API {
constructor(private client: APIClient) {}
/**
* Fetch chain metadata for Chain 138
*/
async getChainMetadata(): Promise<ChainMetadata> {
return this.client.get<ChainMetadata>('/v1/chains/138');
}
/**
* Get transaction receipt
*/
async getTransactionReceipt(txHash: string): Promise<TransactionReceipt> {
return this.client.get<TransactionReceipt>(`/v1/chains/138/transactions/${txHash}/receipt`);
}
/**
* Get transaction logs
*/
async getTransactionLogs(txHash: string): Promise<TransactionReceipt['logs']> {
const receipt = await this.getTransactionReceipt(txHash);
return receipt.logs;
}
/**
* Get block by number
*/
async getBlock(blockNumber: number): Promise<BlockResponse> {
return this.client.get<BlockResponse>(`/v1/chains/138/blocks/${blockNumber}`);
}
/**
* Get latest block
*/
async getLatestBlock(): Promise<BlockResponse> {
return this.client.get<BlockResponse>('/v1/chains/138/blocks/latest');
}
/**
* Send transaction via API (if supported)
*/
async sendTransaction(txData: {
to: string;
value?: string;
data?: string;
gasLimit?: string;
gasPrice?: string;
}): Promise<{ txHash: string }> {
return this.client.post<{ txHash: string }>('/v1/chains/138/transactions', txData);
}
}
/**
* Create Chain 138 API client
*/
export function createChain138API(
config?: Parameters<typeof createAPIClient>[0]
): Chain138API {
const client = createAPIClient(config);
return new Chain138API(client);
}

View File

@@ -0,0 +1,2 @@
export * from './client';
export * from './endpoints';