UNPKG

@robertprp/intents-sdk

Version:

Shogun Network Intent-based cross-chain swaps SDK

115 lines (93 loc) 4.01 kB
import { type Address, getContract, isAddress as isEvmAddress } from 'viem'; import { ChainID, type SupportedEvmChain } from '../../chains.js'; import { isNativeEvmToken, MAX_UINT_128 } from '../../constants.js'; import { InsufficientBalanceError, ValidationError } from '../../errors/index.js'; import { BaseValidator } from '../../utils/base-validator.js'; import type { CreateCrossChainOrderParams } from '../orders/cross-chain.js'; import { ERC20ABI } from './abi/erc20.js'; import { ChainProvider } from './chain-provider.js'; import type { CreateSingleChainOrderParams } from '../orders/single-chain.js'; /** * Chain-specific validator implementations */ export class EvmValidator extends BaseValidator { isValidAddress(address: string): boolean { return isEvmAddress(address); } isValidTokenAddress(tokenAddress: string): boolean { return isEvmAddress(tokenAddress); } isValidAmount(amount: bigint): boolean { return amount > 0n && amount < MAX_UINT_128; } protected getChainName(): string { return 'EVM'; } public async validateCrossChainOrderFeasability( order: CreateCrossChainOrderParams & { user: string }, ): Promise<void> { const chain = order.sourceChainId as SupportedEvmChain; const client = ChainProvider.getClient(chain); const user = order.user as Address; if (isNativeEvmToken(order.sourceTokenAddress)) { throw new ValidationError('Native token is not supported.'); } const ERC20Contract = getContract({ address: order.sourceTokenAddress as Address, abi: ERC20ABI, client: { public: client, chain, }, }); const balance = await ERC20Contract.read.balanceOf([user]); if (balance < order.sourceTokenAmount) { throw new InsufficientBalanceError( `Insufficient balance for token ${order.sourceTokenAddress}. Current balance: ${balance}. Required balance: ${order.sourceTokenAmount}`, ); } // Temporary allowance turn off. This should be handled in the frontend. // const permit2Address = PERMIT2_ADDRESS[chain]; // const allowance = await ERC20Contract.read.allowance([user, permit2Address]); // if (allowance < order.sourceTokenAmount) { // throw new InsufficientAllowanceError( // `Insufficient allowance for token ${order.sourceTokenAddress} on permit2 address ${permit2Address}. Current allowance: ${allowance}. Required allowance: ${order.sourceTokenAmount}`, // ); // } } override async validateSingleChainOrderFeasability( order: CreateSingleChainOrderParams & { user: string }, ): Promise<void> { const chain = order.chainId as SupportedEvmChain; const validSingleChainChains = [ChainID.Hyperliquid, ChainID.Base]; if (!validSingleChainChains.includes(chain)) { throw new ValidationError(`Chain ${chain} is not supported for single chain orders`); } const client = ChainProvider.getClient(chain); const user = order.user as Address; if (isNativeEvmToken(order.tokenIn)) { throw new ValidationError('Native token is not supported.'); } const ERC20Contract = getContract({ address: order.tokenIn as Address, abi: ERC20ABI, client: { public: client, chain, }, }); const balance = await ERC20Contract.read.balanceOf([user]); if (balance < order.amountIn) { throw new InsufficientBalanceError( `Insufficient balance for token ${order.tokenIn}. Current balance: ${balance}. Required balance: ${order.amountIn}`, ); } // const permit2Address = PERMIT2_ADDRESS[chain]; // const allowance = await ERC20Contract.read.allowance([user, permit2Address]); // if (allowance < order.amountIn) { // throw new InsufficientAllowanceError( // `Insufficient allowance for token ${order.tokenIn} on permit2 address ${permit2Address}. Current allowance: ${allowance}. Required allowance: ${order.amountIn}`, // ); // } } }