UNPKG

@robertprp/intents-sdk

Version:

Shogun Network Intent-based cross-chain swaps SDK

123 lines (103 loc) 4.62 kB
import type { CreateCrossChainOrderParams } from '../core/orders/cross-chain.js'; import type { CreateDcaSingleChainOrderParams } from '../core/orders/dca-single-chain.js'; import type { CreateSingleChainOrderParams } from '../core/orders/single-chain.js'; import { ValidationError } from '../errors/index.js'; import type { IChainValidator } from './order-validator.js'; /** * BaseValidator - Abstract class implementing common validation logic * This follows the Template Method pattern */ export abstract class BaseValidator implements IChainValidator { abstract isValidAddress(address: string): boolean; abstract isValidTokenAddress(tokenAddress: string): boolean; abstract isValidAmount(amount: bigint): boolean; protected abstract getChainName(): string; abstract validateCrossChainOrderFeasability(order: CreateCrossChainOrderParams & { user: string }): Promise<void>; abstract validateSingleChainOrderFeasability(order: CreateSingleChainOrderParams & { user: string }): Promise<void>; /** * Validate source chain specific parameters of the order */ async validateSourceChain(order: CreateCrossChainOrderParams & { user: string }): Promise<void> { this.validateTokenAddress(order.sourceTokenAddress); this.validateAmount(order.sourceTokenAmount); this.validateAmount(order.minStablecoinAmount ?? 1n); await this.validateCrossChainOrderFeasability({ ...order, user: order.user }); } async validateSingleChainOrder(order: CreateSingleChainOrderParams & { user: string }): Promise<void> { this.validateTokenAddress(order.tokenIn); this.validateTokenAddress(order.tokenOut); this.validateAmount(order.amountIn); this.validateAmount(order.amountOutMin ?? 1n); if (order.stopLossMaxOut) { this.validateAmount(order.stopLossMaxOut); } if (order.takeProfitMinOut) { this.validateAmount(order.takeProfitMinOut); } await this.validateSingleChainOrderFeasability(order); } /** * Validate destination chain specific parameters of the order */ validateDestinationChain(order: CreateCrossChainOrderParams): void { this.validateAddress(order.destinationAddress); this.validateTokenAddress(order.destinationTokenAddress); this.validateAmount(order.destinationTokenMinAmount ?? 1n); if (order.extraTransfers) { for (const extraTransfer of order.extraTransfers) { this.validateAddress(extraTransfer.receiver); this.validateTokenAddress(extraTransfer.token); this.validateAmount(extraTransfer.amount); } } } abstract validateDcaSingleChainOrderFeasability( order: CreateDcaSingleChainOrderParams & { user: string }, ): Promise<void>; async validateDcaSingleChainOrder(order: CreateDcaSingleChainOrderParams & { user: string }): Promise<void> { this.validateTokenAddress(order.tokenIn); this.validateTokenAddress(order.tokenOut); this.validateAmount(order.amountInPerInterval); this.validateAmount(order.amountOutMin ?? 1n); this.validateAddress(order.destinationAddress); // Validate DCA-specific parameters if (order.totalIntervals <= 0) { throw new ValidationError('Total intervals must be greater than 0'); } if (order.intervalDuration <= 0) { throw new ValidationError('Interval duration must be greater than 0'); } if (order.startTime < 0) { throw new ValidationError('Start time must be non-negative'); } // Validate total amount doesn't overflow const totalAmount = order.amountInPerInterval * BigInt(order.totalIntervals); this.validateAmount(totalAmount); if (order.extraTransfers) { for (const extraTransfer of order.extraTransfers) { this.validateAddress(extraTransfer.receiver); this.validateTokenAddress(extraTransfer.token); this.validateAmount(extraTransfer.amount); } } await this.validateDcaSingleChainOrderFeasability(order); } /** * Helper methods that throw specific validation errors */ protected validateAddress(address: string): void { if (!this.isValidAddress(address)) { throw new ValidationError(`Invalid ${this.getChainName()} address: ${address}`); } } protected validateTokenAddress(tokenAddress: string): void { if (!this.isValidTokenAddress(tokenAddress)) { throw new ValidationError(`Invalid ${this.getChainName()} token address: ${tokenAddress}`); } } protected validateAmount(amount: bigint): void { if (!this.isValidAmount(amount)) { throw new ValidationError(`Amount must be greater than 0. Value: ${amount}`); } } }