@robertprp/intents-sdk
Version:
Shogun Network Intent-based cross-chain swaps SDK
111 lines • 5.13 kB
JavaScript
import { getContract, isAddress as isEvmAddress } from 'viem';
import { ChainID } 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 { ERC20ABI } from './abi/erc20.js';
import { ChainProvider } from './chain-provider.js';
/**
* Chain-specific validator implementations
*/
export class EvmValidator extends BaseValidator {
isValidAddress(address) {
return isEvmAddress(address);
}
isValidTokenAddress(tokenAddress) {
return isEvmAddress(tokenAddress);
}
isValidAmount(amount) {
return amount > 0n && amount < MAX_UINT_128;
}
getChainName() {
return 'EVM';
}
async validateCrossChainOrderFeasability(order) {
const chain = order.sourceChainId;
const client = ChainProvider.getClient(chain);
const user = order.user;
if (isNativeEvmToken(order.sourceTokenAddress)) {
throw new ValidationError('Native token is not supported.');
}
if (order.sourceChainId === ChainID.Hyperliquid && isNativeEvmToken(order.destinationTokenAddress)) {
throw new ValidationError('HYPE native token as destination address is not supported.');
}
const ERC20Contract = getContract({
address: order.sourceTokenAddress,
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}`,
// );
// }
}
async validateSingleChainOrderFeasability(order) {
const chain = order.chainId;
const validSingleChainChains = [ChainID.Hyperliquid, ChainID.Base];
if (!validSingleChainChains.includes(chain)) {
throw new ValidationError(`Chain ${chain} is not supported for single chain orders`);
}
if (order.chainId === ChainID.Hyperliquid && isNativeEvmToken(order.tokenOut)) {
throw new ValidationError('HYPE native token as destination address is not supported.');
}
const client = ChainProvider.getClient(chain);
const user = order.user;
if (isNativeEvmToken(order.tokenIn)) {
throw new ValidationError('Native token is not supported.');
}
const ERC20Contract = getContract({
address: order.tokenIn,
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}`,
// );
// }
}
async validateDcaSingleChainOrderFeasability(order) {
const chain = order.chainId;
const client = ChainProvider.getClient(chain);
const user = order.user;
if (isNativeEvmToken(order.tokenIn)) {
throw new ValidationError('Native token is not supported for DCA orders.');
}
const ERC20Contract = getContract({
address: order.tokenIn,
abi: ERC20ABI,
client: {
public: client,
chain,
},
});
const totalAmountIn = order.amountInPerInterval * BigInt(order.totalIntervals);
const balance = await ERC20Contract.read.balanceOf([user]);
if (balance < totalAmountIn) {
throw new InsufficientBalanceError(`Insufficient balance for DCA order. Token: ${order.tokenIn}. Current balance: ${balance}. Required total: ${totalAmountIn}`);
}
}
}
//# sourceMappingURL=validator.js.map