UNPKG

@shogun-sdk/money-legos

Version:

Shogun Money Legos: clients and types for quotes, memes, prices, balances, fees, validations, etc.

124 lines (102 loc) 3.67 kB
import { InfoAPI } from './rest/info.js'; import { ExchangeAPI } from './rest/exchange.js'; import { RateLimiter } from './utils/rateLimiter.js'; import * as CONSTANTS from './types/constants.js'; import { CustomOperations } from './rest/custom.js'; import { ethers } from 'ethers'; import { SymbolConversion } from './utils/symbolConversion.js'; import { AuthenticationError } from './utils/errors.js'; export interface HyperliquidConfig { privateKey?: string; testnet?: boolean; walletAddress?: string; vaultAddress?: string; maxReconnectAttempts?: number; } export class Hyperliquid { public info: InfoAPI; public exchange: ExchangeAPI; public custom: CustomOperations; public symbolConversion: SymbolConversion; private rateLimiter: RateLimiter; private isValidPrivateKey: boolean = false; private _initialized: boolean = false; private _initializing: Promise<void> | null = null; private vaultAddress?: string | null = null; constructor(params: HyperliquidConfig = {}) { const { privateKey, vaultAddress } = params; const baseURL = CONSTANTS.BASE_URL; this.rateLimiter = new RateLimiter(); this.symbolConversion = new SymbolConversion(baseURL, this.rateLimiter); this.vaultAddress = vaultAddress || null; // Initialize info API this.info = new InfoAPI(baseURL, this.rateLimiter, this.symbolConversion, this); // Create proxy objects for exchange and custom this.exchange = this.createAuthenticatedProxy(ExchangeAPI); this.custom = this.createAuthenticatedProxy(CustomOperations); if (privateKey) { this.initializePrivateKey(privateKey); } } public async connect(): Promise<void> { if (!this._initialized) { if (!this._initializing) { this._initializing = this.initialize(); } await this._initializing; } } private async initialize(): Promise<void> { if (this._initialized) return; try { // Initialize symbol conversion first await this.symbolConversion.initialize(); this._initialized = true; this._initializing = null; } catch (error) { this._initializing = null; throw error; } } public async ensureInitialized(): Promise<void> { await this.connect(); } private initializePrivateKey(privateKey: string): void { try { const formattedPrivateKey = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`; new ethers.Wallet(formattedPrivateKey); // Validate the private key this.exchange = new ExchangeAPI( formattedPrivateKey, this.rateLimiter, this.symbolConversion, this, this.vaultAddress, ); this.custom = new CustomOperations(this.exchange, this.info, formattedPrivateKey, this.symbolConversion, this); this.isValidPrivateKey = true; } catch (error) { console.warn('Invalid private key provided. Some functionalities will be limited.'); this.isValidPrivateKey = false; } } private createAuthenticatedProxy<T extends object>(_Class: new (...args: any[]) => T): T { return new Proxy({} as T, { get: (target, prop) => { if (!this.isValidPrivateKey) { throw new AuthenticationError('Invalid or missing private key. This method requires authentication.'); } return target[prop as keyof T]; }, }); } // Modify existing methods to check initialization public isAuthenticated(): boolean { this.ensureInitialized(); return this.isValidPrivateKey; } disconnect(): void { this.ensureInitialized(); } } export * from './types/index.js'; export * from './utils/signing.js';