@smoothsend/sdk
Version:
Multi-chain gasless transaction SDK for seamless dApp integration
563 lines (553 loc) • 19.2 kB
TypeScript
import { AxiosRequestConfig } from 'axios';
type SupportedChain = 'avalanche' | 'aptos-testnet';
type ChainEcosystem = 'evm' | 'aptos';
declare const CHAIN_ECOSYSTEM_MAP: Record<SupportedChain, ChainEcosystem>;
interface SuccessResponse {
success: true;
}
interface ErrorResponse {
success: false;
error: string;
details?: string[];
requestId?: string;
}
interface ChainInfo {
name: string;
displayName: string;
chainId: number;
explorerUrl: string;
tokens: string[];
}
interface TokenInfo {
symbol: string;
address: string;
decimals: number;
name: string;
}
interface ChainConfig {
name: string;
displayName: string;
chainId: number;
rpcUrl: string;
relayerUrl: string;
explorerUrl: string;
tokens: string[];
nativeCurrency: {
name: string;
symbol: string;
decimals: number;
};
}
interface TransferRequest {
from: string;
to: string;
token: string;
amount: string;
chain: SupportedChain;
}
interface TransferQuoteResponse extends SuccessResponse {
chainName: string;
token: string;
amount: string;
relayerFee: string;
total: string;
feePercentage: number;
contractAddress: string;
}
interface TransferQuote {
amount: string;
relayerFee: string;
total: string;
feePercentage: number;
contractAddress: string;
aptosTransactionData?: any;
}
interface RelayTransferResponse extends SuccessResponse {
transferId: string;
txHash: string;
blockNumber: number;
gasUsed: string;
explorerUrl: string;
fee: string;
executionTime: number;
}
interface TransferResult {
success: boolean;
txHash: string;
blockNumber?: number;
gasUsed?: string;
transferId?: string;
explorerUrl?: string;
fee?: string;
executionTime?: number;
gasFeePaidBy?: string;
userPaidAPT?: boolean;
transparency?: string;
vmStatus?: string;
sender?: string;
chain?: string;
relayerFee?: string;
message?: string;
}
interface BatchTransferRequest {
transfers: TransferRequest[];
chain: SupportedChain;
}
interface EVMTransferData {
chainName: string;
from: string;
to: string;
tokenSymbol: string;
amount: string;
relayerFee: string;
nonce: string;
deadline: number;
signature: string;
permitData?: {
value: string;
deadline: number;
v: number;
r: string;
s: string;
};
}
type AvalancheTransferData = EVMTransferData;
interface AptosTransferData {
transactionBytes: number[];
authenticatorBytes: number[];
functionName?: string;
fromAddress?: string;
toAddress?: string;
amount?: string;
coinType?: string;
}
interface SignatureData {
domain: any;
types: any;
message: any;
primaryType: string;
metadata?: {
chain?: SupportedChain;
fromAddress?: string;
toAddress?: string;
amount?: string;
token?: string;
relayerFee?: string;
signatureVersion?: string;
requiresPublicKey?: boolean;
verificationMethod?: string;
};
}
interface SignedTransferData {
transferData: any;
signature: string;
signatureType: 'EIP712' | 'Ed25519';
publicKey?: string;
metadata?: {
signatureVersion?: string;
verificationMethod?: string;
requiresPublicKey?: boolean;
};
}
interface TokenBalance {
token: string;
balance: string;
decimals: number;
symbol: string;
name?: string;
}
interface TransferQuoteRequest {
chainName: string;
token: string;
amount: string;
}
interface PrepareSignatureRequest {
chainName: string;
from: string;
to: string;
tokenSymbol: string;
amount: string;
relayerFee: string;
nonce: string;
deadline: number;
}
interface RelayTransferRequest {
chainName: string;
from: string;
to: string;
tokenSymbol: string;
amount: string;
relayerFee: string;
nonce: string;
deadline: number;
signature: string;
permitData?: PermitData;
}
interface BatchRelayTransferRequest {
chainName: string;
transfers: RelayTransferRequest[];
}
interface EstimateGasRequest {
chainName: string;
transfers: TransferData[];
}
interface TransferData {
from: string;
to: string;
token: string;
amount: string;
relayerFee: string;
nonce: string;
deadline: number;
signature: string;
permitData?: PermitData;
}
interface PermitData {
value: string;
deadline: number;
v: number;
r: string;
s: string;
}
interface PrepareSignatureResponse extends SuccessResponse {
typedData: any;
messageHash: string;
message: string;
}
interface GasEstimateResponse extends SuccessResponse {
chainName: string;
gasEstimate: string;
gasPrice: string;
estimatedCost: string;
transferCount: number;
}
interface HealthResponse extends SuccessResponse {
status: string;
timestamp: string;
version: string;
}
interface DomainSeparatorResponse extends SuccessResponse {
chainName: string;
domainSeparator: string;
}
interface TransferStatusResponse extends SuccessResponse {
chainName: string;
transferHash: string;
executed: boolean;
}
declare class SmoothSendError extends Error {
code: string;
chain?: SupportedChain | undefined;
details?: any | undefined;
constructor(message: string, code: string, chain?: SupportedChain | undefined, details?: any | undefined);
}
declare const APTOS_ERROR_CODES: {
readonly MISSING_SIGNATURE: "APTOS_MISSING_SIGNATURE";
readonly MISSING_PUBLIC_KEY: "APTOS_MISSING_PUBLIC_KEY";
readonly INVALID_SIGNATURE_FORMAT: "APTOS_INVALID_SIGNATURE_FORMAT";
readonly INVALID_PUBLIC_KEY_FORMAT: "APTOS_INVALID_PUBLIC_KEY_FORMAT";
readonly ADDRESS_MISMATCH: "APTOS_ADDRESS_MISMATCH";
readonly SIGNATURE_VERIFICATION_FAILED: "APTOS_SIGNATURE_VERIFICATION_FAILED";
readonly MISSING_TRANSACTION_DATA: "APTOS_MISSING_TRANSACTION_DATA";
readonly INVALID_TRANSACTION_FORMAT: "APTOS_INVALID_TRANSACTION_FORMAT";
readonly EMPTY_ADDRESS: "APTOS_EMPTY_ADDRESS";
readonly INVALID_ADDRESS_FORMAT: "APTOS_INVALID_ADDRESS_FORMAT";
readonly QUOTE_ERROR: "APTOS_QUOTE_ERROR";
readonly EXECUTE_ERROR: "APTOS_EXECUTE_ERROR";
readonly BALANCE_ERROR: "APTOS_BALANCE_ERROR";
readonly TOKEN_INFO_ERROR: "APTOS_TOKEN_INFO_ERROR";
readonly STATUS_ERROR: "APTOS_STATUS_ERROR";
readonly MOVE_CALL_ERROR: "APTOS_MOVE_CALL_ERROR";
readonly UNSUPPORTED_TOKEN: "APTOS_UNSUPPORTED_TOKEN";
};
type AptosErrorCode = typeof APTOS_ERROR_CODES[keyof typeof APTOS_ERROR_CODES];
interface ApiResponse<T = any> {
success: boolean;
data?: T;
error?: string;
details?: string[];
requestId?: string;
errorCode?: string;
chain?: SupportedChain;
timestamp?: string;
}
interface SmoothSendConfig {
timeout?: number;
retries?: number;
customChainConfigs?: Partial<Record<SupportedChain, Partial<ChainConfig>>>;
useDynamicConfig?: boolean;
configCacheTtl?: number;
relayerUrls?: {
evm?: string;
aptos?: string;
};
}
interface TransferEvent {
type: 'transfer_initiated' | 'transfer_signed' | 'transfer_submitted' | 'transfer_confirmed' | 'transfer_failed';
data: any;
timestamp: number;
chain: SupportedChain;
}
type EventListener = (event: TransferEvent) => void;
interface IChainAdapter {
readonly chain: SupportedChain;
readonly config: ChainConfig;
getQuote(request: TransferRequest): Promise<TransferQuote>;
prepareTransfer(request: TransferRequest, quote: TransferQuote): Promise<SignatureData>;
executeTransfer(signedData: SignedTransferData): Promise<TransferResult>;
executeBatchTransfer?(signedTransfers: SignedTransferData[]): Promise<TransferResult[]>;
getBalance?(address: string, token?: string): Promise<TokenBalance[]>;
getTokenInfo(token: string): Promise<TokenInfo>;
getNonce(address: string): Promise<string>;
getTransactionStatus(txHash: string): Promise<any>;
validateAddress(address: string): boolean;
validateAmount(amount: string, token: string): Promise<boolean>;
}
declare class SmoothSendSDK {
private adapters;
private eventListeners;
private config;
private initialized;
private initializationPromise;
constructor(config?: SmoothSendConfig);
/**
* Initialize adapters with dynamic or static configuration
*/
private initializeAdapters;
private _doInitialize;
private initializeDynamicAdapters;
private initializeStaticAdapters;
private createAdapter;
/**
* Fetch supported chains from both relayers
*/
private fetchSupportedChains;
/**
* Fetch chain configuration from the appropriate relayer
*/
private fetchChainConfig;
/**
* Get default configuration for a chain (fallback when dynamic config fails)
*/
private getDefaultChainConfig;
/**
* Refresh chain configurations from relayers
*/
refreshChainConfigs(): Promise<void>;
addEventListener(listener: EventListener): void;
removeEventListener(listener: EventListener): void;
private emitEvent;
getQuote(request: TransferRequest): Promise<TransferQuote>;
prepareTransfer(request: TransferRequest, quote: TransferQuote): Promise<SignatureData>;
executeTransfer(signedData: SignedTransferData, chain: SupportedChain): Promise<TransferResult>;
transfer(request: TransferRequest, signer: any): Promise<TransferResult>;
batchTransfer(request: BatchTransferRequest, signer: any): Promise<TransferResult[]>;
getBalance(chain: SupportedChain, address: string, token?: string): Promise<TokenBalance[]>;
getTokenInfo(chain: SupportedChain, token: string): Promise<TokenInfo>;
getNonce(chain: SupportedChain, address: string): Promise<string>;
getTransactionStatus(chain: SupportedChain, txHash: string): Promise<any>;
validateAddress(chain: SupportedChain, address: string): Promise<boolean>;
validateAmount(chain: SupportedChain, amount: string, token: string): Promise<boolean>;
getSupportedChains(): Promise<SupportedChain[]>;
getChainConfig(chain: SupportedChain): Promise<ChainConfig>;
isChainSupported(chain: string): Promise<boolean>;
/**
* Get supported tokens for a specific chain (from dynamic config)
*/
getSupportedTokens(chain: SupportedChain): Promise<string[]>;
/**
* Health check endpoint
*/
getHealth(): Promise<HealthResponse>;
/**
* Get supported blockchain networks
*/
getSupportedChainsInfo(): Promise<ChainInfo[]>;
/**
* Get supported tokens for a specific chain
*/
getSupportedTokensForChain(chainName: string): Promise<TokenInfo[]>;
/**
* Estimate gas cost for transfers
*/
estimateGas(chainName: string, transfers: any[]): Promise<GasEstimateResponse>;
/**
* Get EIP-712 domain separator for a specific chain
*/
getDomainSeparator(chainName: string): Promise<DomainSeparatorResponse>;
/**
* Check transfer execution status
*/
getTransferStatus(chainName: string, transferHash: string): Promise<TransferStatusResponse>;
/**
* Check if a chain belongs to a specific ecosystem
*/
getChainEcosystem(chain: SupportedChain): ChainEcosystem;
private getAdapter;
static getSupportedChains(): SupportedChain[];
static getChainConfig(chain: SupportedChain): ChainConfig;
static getAllChainConfigs(): Record<SupportedChain, ChainConfig>;
}
/**
* EVM Multi-Chain Adapter
* Handles all EVM-compatible chains (Avalanche, Polygon, Ethereum, Arbitrum, Base)
* Routes requests to the appropriate chain endpoint on the EVM relayer
*/
declare class EVMAdapter implements IChainAdapter {
readonly chain: SupportedChain;
readonly config: ChainConfig;
private httpClient;
constructor(chain: SupportedChain, config: ChainConfig, relayerUrl: string);
/**
* Build API path with chain name for EVM relayer
* EVM relayer uses /chains/{chainName} prefix for most endpoints
*/
private getApiPath;
getQuote(request: TransferRequest): Promise<TransferQuote>;
prepareTransfer(request: TransferRequest, quote: TransferQuote): Promise<SignatureData>;
executeTransfer(signedData: SignedTransferData): Promise<TransferResult>;
/**
* EVM-specific batch transfer support
* Takes advantage of the EVM relayer's native batch capabilities
*/
executeBatchTransfer?(signedTransfers: SignedTransferData[]): Promise<TransferResult[]>;
getTokenInfo(token: string): Promise<TokenInfo>;
getNonce(address: string): Promise<string>;
getTransactionStatus(txHash: string): Promise<any>;
validateAddress(address: string): boolean;
validateAmount(amount: string, token: string): Promise<boolean>;
/**
* EVM-specific gas estimation
*/
estimateGas(transfers: any[]): Promise<any>;
/**
* EVM-specific permit support check
*/
supportsPermit(tokenAddress: string): Promise<boolean>;
}
/**
* Aptos Multi-Chain Adapter
* Handles all Aptos chains (aptos-testnet, aptos-mainnet)
* Routes requests to the appropriate chain endpoint on the Aptos relayer
* Supports Aptos-specific features like gasless transactions and Move-based contracts
*/
declare class AptosAdapter implements IChainAdapter {
readonly chain: SupportedChain;
readonly config: ChainConfig;
private httpClient;
constructor(chain: SupportedChain, config: ChainConfig, relayerUrl: string);
/**
* Build API path with chain name for Aptos relayer
*/
private getApiPath;
getQuote(request: TransferRequest): Promise<TransferQuote>;
prepareTransfer(request: TransferRequest, quote: TransferQuote): Promise<SignatureData>;
executeTransfer(signedData: SignedTransferData): Promise<TransferResult>;
getBalance(address: string, token?: string): Promise<TokenBalance[]>;
getTokenInfo(token: string): Promise<TokenInfo>;
getNonce(address: string): Promise<string>;
getTransactionStatus(txHash: string): Promise<any>;
validateAddress(address: string): boolean;
validateAmount(amount: string, token: string): Promise<boolean>;
/**
* Get Aptos token address from symbol
*/
private getAptosTokenAddress;
/**
* Build Aptos explorer URL for transaction
*/
private buildAptosExplorerUrl;
/**
* Validate serialized transaction data for the new safe endpoint
* @param signedData The signed transfer data to validate
*/
private validateSerializedTransactionData;
/**
* Enhanced address validation with detailed error messages
* @param address The address to validate
* @returns true if valid, throws error if invalid
*/
validateAddressStrict(address: string): boolean;
/**
* Verify that a public key corresponds to an expected address
* This mirrors the enhanced verification in the relayer
* @param publicKey The public key to verify
* @param expectedAddress The expected address
* @returns true if they match
*/
verifyPublicKeyAddress(publicKey: string, expectedAddress: string): Promise<boolean>;
/**
* Enhanced transaction preparation with better signature data structure
* @param request Transfer request
* @param quote Transfer quote
* @returns Signature data with enhanced structure
*/
prepareTransferEnhanced(request: TransferRequest, quote: TransferQuote): Promise<SignatureData & {
metadata: any;
}>;
/**
* Aptos-specific Move contract interaction
*/
callMoveFunction(functionName: string, args: any[]): Promise<any>;
}
declare const CHAIN_CONFIGS: Record<SupportedChain, ChainConfig>;
declare function getChainConfig(chain: SupportedChain): ChainConfig;
declare function getAllChainConfigs(): Record<SupportedChain, ChainConfig>;
declare const TOKEN_DECIMALS: Record<string, number>;
declare function getTokenDecimals(token: string): number;
interface DynamicChainConfig extends ChainConfig {
tokens: string[];
contractAddress?: string;
feeSettings?: {
baseFeeBps: number;
minFeeWei: string;
maxFeeBps: number;
};
}
declare class ChainConfigService {
private configCache;
private cacheExpiry;
private readonly CACHE_TTL;
/**
* Fetch chain configuration from relayer's API endpoints
*/
fetchChainConfig(relayerUrl: string, chainName?: string): Promise<DynamicChainConfig[]>;
/**
* Get configuration for a specific supported chain
*/
getChainConfig(chain: SupportedChain, fallbackConfig?: ChainConfig): Promise<DynamicChainConfig>;
/**
* Get all available chain configurations
*/
getAllChainConfigs(fallbackConfigs?: Record<SupportedChain, ChainConfig>): Promise<Record<string, DynamicChainConfig>>;
/**
* Clear the configuration cache
*/
clearCache(): void;
/**
* Set custom cache TTL
*/
setCacheTtl(ttlMs: number): void;
private mapRelayerChainToConfig;
private getRelayerUrlForChain;
private matchesChain;
private matchesChainName;
private getChainKey;
private getDefaultRpcUrl;
private getNativeCurrencyForChain;
private getDefaultTokensForChain;
}
declare const chainConfigService: ChainConfigService;
declare class HttpClient {
private client;
constructor(baseURL: string, timeout?: number);
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
private handleError;
retry<T>(operation: () => Promise<ApiResponse<T>>, maxRetries?: number, delay?: number): Promise<ApiResponse<T>>;
}
declare const VERSION = "2.0.0-beta.1";
export { APTOS_ERROR_CODES, AptosAdapter, CHAIN_CONFIGS, CHAIN_ECOSYSTEM_MAP, ChainConfigService, EVMAdapter, HttpClient, SmoothSendError, SmoothSendSDK, TOKEN_DECIMALS, VERSION, chainConfigService, SmoothSendSDK as default, getAllChainConfigs, getChainConfig, getTokenDecimals };
export type { ApiResponse, AptosErrorCode, AptosTransferData, AvalancheTransferData, BatchRelayTransferRequest, BatchTransferRequest, ChainConfig, ChainEcosystem, ChainInfo, DomainSeparatorResponse, DynamicChainConfig, EVMTransferData, ErrorResponse, EstimateGasRequest, EventListener, GasEstimateResponse, HealthResponse, IChainAdapter, PermitData, PrepareSignatureRequest, PrepareSignatureResponse, RelayTransferRequest, RelayTransferResponse, SignatureData, SignedTransferData, SmoothSendConfig, SuccessResponse, SupportedChain, TokenBalance, TokenInfo, TransferData, TransferEvent, TransferQuote, TransferQuoteRequest, TransferQuoteResponse, TransferRequest, TransferResult, TransferStatusResponse };