Skip to Content
Packages@cfxdevkit/automation

@cfxdevkit/automation

Automation strategies (limit, dca, stop-loss, scheduled).

Install

pnpm add @cfxdevkit/automation

Scope: Off-chain automation strategies executable by framework/executor.

Responsibilities

  • Strategy interface (evaluate, buildTx, verify)
  • Built-in strategies: limit order, DCA, TWAP, condition-based swaps
  • Strategy persistence schema (via JobRepository, ExecutionRepository)
  • Backtesting helpers (via PriceChecker, SwappiPriceSource, GeckoTerminalPriceSource)
  • Safety checks and retry logic (via SafetyConfig, RetryQueue)

Non-goals

  • Keeper transport / queue (lives in framework/executor).
  • Project-specific UI (lives in projects/cas/apps/frontend).

Origin: cas/conflux-cas/worker patterns + cas/conflux-sdk automation types.

Installation

npm install @cfxdevkit/automation

Sub-paths

Sub-pathExports
.92 symbols
./db11 symbols

Key Concepts

Strategies

Strategies define when and how to execute an automation job. Each strategy implements:

  • evaluate(context: StrategyEvalContext): EvalResult — determines if job should run
  • buildTx(params: TParams): BuildSwapCalldataInput — constructs transaction calldata
  • verify(result: ExecuteResult): boolean — confirms successful execution

Supported strategies:

  • LimitOrderStrategy
  • DCAStrategy
  • TWAPStrategy
  • SwapStrategy (for condition-based swaps)

Execution Flow

  1. Keeper polls JobRepository for active jobs.
  2. For each job, StrategyEvaluator runs evaluate() using PriceSource.
  3. If triggered, buildTx() prepares calldata.
  4. SwapExecutorClient submits transaction via AutomationManager.
  5. ExecutionRepository records outcome; RetryQueue handles failures.

Safety & Reliability

  • SafetyConfig defines thresholds (e.g., max slippage, price deviation).
  • SafetyContext and SafetyCheckResult enforce constraints before execution.
  • RetryQueue manages transient failures with exponential backoff.

Usage

Create a Limit Order Job

import { LimitOrderStrategy, MemoryJobRepository, SwappiPriceSource, PriceChecker, DEFAULT_SAFETY_CONFIG, } from '@cfxdevkit/automation'; const priceSource = new SwappiPriceSource({ routerAddress: SWAPPI_ADDRESSES.router, quoteReader: new SwappiQuoteReader(), }); const jobRepo = new MemoryJobRepository(); const priceChecker = new PriceChecker(priceSource, DEFAULT_SAFETY_CONFIG); const strategy = new LimitOrderStrategy(priceChecker); const job = { id: 'limit-0x123', type: 'LIMIT_ORDER', params: { tokenIn: '0x...', tokenOut: '0x...', amountIn: 1_000_000n, amountOutMin: 950_000n, deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), }, strategy: strategy, }; await jobRepo.add(job);

Run the Keeper

import { Keeper } from '@cfxdevkit/automation'; const keeper = new Keeper({ jobRepo, executionRepo: new MemoryExecutionRepository(), retryQueue: { maxRetries: 3, baseDelayMs: 1000 }, priceSource, safetyConfig: DEFAULT_SAFETY_CONFIG, }); keeper.start();

Backtest with Historical Prices

import { GeckoTerminalPriceSource } from '@cfxdevkit/automation'; const historicalSource = new GeckoTerminalPriceSource({ poolAddress: '0x...', network: 'conflux-espace', }); const backtestResult = await priceChecker.evaluate({ job, timestamp: 1700000000, priceSource: historicalSource, });

API Reference

See full exports in API.md. Key classes include:

  • AutomationManagerClient — interacts with on-chain automation manager
  • KeeperClientImpl — low-level keeper client for custom transports
  • SwappiPriceSource / GeckoTerminalPriceSource — price feeds
  • MemoryJobRepository / MemoryExecutionRepository — in-memory storage (use for testing)
  • RetryQueue — handles failed executions

Note: For production use, implement custom JobRepository and ExecutionRepository backed by persistent storage (e.g., PostgreSQL, Redis).

API REFERENCE EXCERPT

export declare const __packageName: "@cfxdevkit/automation"; export declare const PRICE_SCALE: bigint; export declare const DEFAULT_DCA_DUE_BUFFER_SECONDS = 15; export declare const AUTOMATION_MANAGER_ADDRESSES: { confluxESpace: string; confluxCore: string; }; export declare const AUTOMATION_MANAGER_ABI: readonly [ // ... ABI entries ]; export declare const DEFAULT_SAFETY_CONFIG: SafetyConfig; export declare const SWAPPI_ROUTER_ABI: readonly [ // ... ABI entries ]; export declare const SWAPPI_ADDRESSES: { confluxESpace: string; confluxCore: string; }; export interface PriceSource { getSpotPrice(tokenIn: string, tokenOut: string): Promise<bigint>; getHistoricalPrice(tokenIn: string, tokenOut: string, timestamp: number): Promise<bigint>; } export interface LimitOrderCheckResult { triggered: boolean; reason?: string; } export interface DCACheckResult { due: boolean; nextDueTime?: number; } export interface KeeperClient { execute(job: ExecutableJob): Promise<ExecuteResult>; } export interface AutomationManagerActions { execute(job: ExecutableJob): Promise<ExecuteResult>; } export interface AutomationManagerClientConfig { chainId: number; signer: Signer; } export interface KeeperClientImplConfig { automationManager: AutomationManagerActions; } export interface KeeperConfig { jobRepo: JobRepository; executionRepo: ExecutionRepository; retryQueue: RetryQueueOptions; priceSource: PriceSource; safetyConfig: SafetyConfig; } export interface KeeperDeps { jobRepo: JobRepository; executionRepo: ExecutionRepository; retryQueue: RetryQueue; priceSource: PriceSource; safetyConfig: SafetyConfig; } export interface GeckoTerminalPriceSourceOptions { poolAddress: string; network: 'conflux-espace' | 'conflux-core'; } export interface SwappiQuoteReader { getSwapQuote(input: SwapQuoteInput): Promise<SwapExecuteResult>; } export interface SwappiPriceSourceOptions { routerAddress: string; quoteReader: SwappiQuoteReader; } export interface JobListFilter { status?: 'ACTIVE' | 'COMPLETED' | 'FAILED'; type?: JobType; } export interface JobUpdate { status?: 'ACTIVE' | 'COMPLETED' | 'FAILED'; } export interface JobRepository { add(job: ExecutableJob): Promise<void>; get(id: string): Promise<ExecutableJob | null>; list(filter?: JobListFilter): Promise<ExecutableJob[]>; update(id: string, update: JobUpdate): Promise<void>; } export interface ExecutionRecord { id: string; jobId: string; status: 'PENDING' | 'SUCCESS' | 'FAILED'; timestamp: number; txHash?: string; error?: string; } export interface NewExecutionRecord { jobId: string; status: 'PENDING' | 'SUCCESS' | 'FAILED'; txHash?: string; error?: string; } export interface ExecutionRepository { add(record: NewExecutionRecord): Promise<void>; listByJob(jobId: string): Promise<ExecutionRecord[]>; } export interface RetryQueueOptions { maxRetries: number; baseDelayMs: number; } export interface SafetyConfig { maxSlippageBps: number; maxPriceDeviationBps: number; } export interface SafetyContext { job: ExecutableJob; currentPrice: bigint; expectedPrice?: bigint; } export interface SafetyViolation { type: 'SLIPPAGE' | 'PRICE_DEVIATION'; message: string; } export interface SafetyCheckResult { passed: boolean; violations?: SafetyViolation[]; } export interface LimitOrderStrategy { evaluate(context: StrategyEvalContext): Promise<LimitOrderCheckResult>; buildTx(params: LimitOrderParams): BuildSwapCalldataInput; verify(result: ExecuteResult): boolean; } export interface DCAStrategy { evaluate(context: StrategyEvalContext): Promise<DCACheckResult>; buildTx(params: DCAParams): BuildSwapCalldataInput; verify(result: ExecuteResult): boolean; } export interface TWAPStrategy { evaluate(context: StrategyEvalContext): Promise<EvalResult>; buildTx(params: TWAPParams): BuildSwapCalldataInput; verify(result: ExecuteResult): boolean; } export interface SwapStrategy { evaluate(context: StrategyEvalContext): Promise<EvalResult>; buildTx(params: SwapParams): BuildSwapCalldataInput; verify(result: ExecuteResult): boolean; } export interface StrategyEvalContext { job: ExecutableJob; timestamp: number; priceSource: PriceSource; } export interface StrategyEvaluator<TJob extends ExecutableJob = ExecutableJob> { evaluate(job: TJob, context: StrategyEvalContext): Promise<EvalResult>; } export interface BuildSwapCalldataInput { calldata: string; value?: bigint; } export interface SwapExecutorClient { execute(input: SwapExecuteInput): Promise<ExecuteResult>; } export interface SwapExecutorOptions { chainId: number; signer: Signer; } export interface SwapRouterAddresses { router: string; factory: string; } export interface SwapQuoteInput { tokenIn: string; tokenOut: string; amountIn: bigint; recipient: string; } export interface SwapExecuteInput extends SwapQuoteInput { deadline: bigint; slippageTolerance: number; } export interface SwapExecuteResult { amountOut: bigint; path: string[]; } export interface SwapReceiptLog { address: string; topics: string[]; data: string; } export interface SwapReceipt { status: number; logs: SwapReceiptLog[]; } export interface BaseJobParams { tokenIn: string; tokenOut: string; amountIn: bigint; } export interface LimitOrderParams extends BaseJobParams { amountOutMin: bigint; deadline: bigint; } export interface DCAParams extends BaseJobParams { amountOutMin: bigint; intervalSeconds: number; totalDurationSeconds: number; totalAmountIn: bigint; } export interface TWAPParams extends BaseJobParams { amountOutMin: bigint; durationSeconds: number; intervalSeconds: number; } export interface SwapParams extends BaseJobParams { amountOutMin: bigint; deadline: bigint; condition: 'BELOW' | 'ABOVE'; threshold: bigint; } export interface BaseJob<TType extends JobType, TParams> { id: string; type: TType; params: TParams; strategy: Strategy; } export interface ExecuteResult { success: boolean; txHash?: string; error?: string; } export interface TickResult { nextTickTime?: number; } export interface EvalResult { triggered: boolean; tickResult?: TickResult; } export declare class PriceChecker { constructor(priceSource: PriceSource, config: SafetyConfig); evaluate(context: StrategyEvalContext): Promise<EvalResult>; } export declare class AutomationManagerClient implements KeeperClient { constructor(config: AutomationManagerClientConfig); execute(job: ExecutableJob): Promise<ExecuteResult>; } export declare class KeeperClientImpl implements KeeperClient { constructor(config: KeeperClientImplConfig); execute(job: ExecutableJob): Promise<ExecuteResult>; } export declare class Keeper { constructor(config: KeeperConfig); start(): void; stop(): void; } export declare class GeckoTerminalPriceSource implements PriceSource { constructor(options: GeckoTerminalPriceSourceOptions); getSpotPrice(tokenIn: string, tokenOut: string): Promise<bigint>; getHistoricalPrice(tokenIn: string, tokenOut: string, timestamp: number): Promise<bigint>; } export declare class SwappiPriceSource implements PriceSource { constructor(options: SwappiPriceSourceOptions); getSpotPrice(tokenIn: string, tokenOut: string): Promise<bigint>; getHistoricalPrice(tokenIn: string, tokenOut: string, timestamp: number): Promise<bigint>; } export declare class MemoryJobRepository implements JobRepository { add(job: ExecutableJob): Promise<void>; get(id: string): Promise<ExecutableJob | null>; list(filter?: JobListFilter): Promise<ExecutableJob[]>; update(id: string, update: JobUpdate): Promise<void>; } export declare class MemoryExecutionRepository implements ExecutionRepository { add(record: NewExecutionRecord): Promise<void>; listByJob(jobId: string): Promise<ExecutionRecord[]>; }

Tier

Tier 2 — domains — May import Tier 0 and Tier 1 packages.

API Reference

.

Usage

import { Keeper, DCAStrategy } from '@cfxdevkit/automation'; const keeper = new Keeper(config); await keeper.run();
// Package name identifier for runtime introspection export declare const __packageName: "@cfxdevkit/automation"; // Scaling factor used for price calculations export declare const PRICE_SCALE: bigint; // Default buffer in seconds for DCA execution timing export declare const DEFAULT_DCA_DUE_BUFFER_SECONDS = 15; // Mapping of automation manager addresses across networks export declare const AUTOMATION_MANAGER_ADDRESSES: { // ABI for the automation manager contract export declare const AUTOMATION_MANAGER_ABI: readonly [ // Default safety configuration for automation execution export declare const DEFAULT_SAFETY_CONFIG: SafetyConfig; // ABI for the Swappi router contract export declare const SWAPPI_ROUTER_ABI: readonly [ // Mapping of Swappi related addresses export declare const SWAPPI_ADDRESSES: { // Interface for providing token price data export interface PriceSource { // Result of a limit order condition check export interface LimitOrderCheckResult { // Result of a DCA timing check export interface DCACheckResult { // Interface for the keeper client implementation export interface KeeperClient { // Available actions for the automation manager export interface AutomationManagerActions { // Configuration for the automation manager client export interface AutomationManagerClientConfig { // Configuration for the keeper client implementation export interface KeeperClientImplConfig { // Configuration for the keeper instance export interface KeeperConfig { // Dependencies required by the keeper export interface KeeperDeps { // Options for the GeckoTerminal price source export interface GeckoTerminalPriceSourceOptions { // Interface for reading quotes from Swappi export interface SwappiQuoteReader { // Options for the Swappi price source export interface SwappiPriceSourceOptions { // Filter criteria for retrieving job lists export interface JobListFilter { // Represents an update to a job export interface JobUpdate { // Interface for job persistence and retrieval export interface JobRepository { // Record of a single job execution export interface ExecutionRecord { // Data required to create a new execution record export interface NewExecutionRecord { // Interface for execution history persistence export interface ExecutionRepository { // Options for the retry queue mechanism export interface RetryQueueOptions { // Configuration for safety constraints export interface SafetyConfig { // Context provided during safety evaluations export interface SafetyContext { // Details of a safety constraint violation export interface SafetyViolation { // Result of a safety check evaluation export interface SafetyCheckResult { // Parameters for a limit order strategy export interface LimitOrderStrategy { // Parameters for a DCA strategy export interface DCAStrategy { // Parameters for a TWAP strategy export interface TWAPStrategy { // Parameters for a swap strategy export interface SwapStrategy { // Context for strategy evaluation export interface StrategyEvalContext { // Interface for evaluating if a job should be executed export interface StrategyEvaluator<TJob extends ExecutableJob = ExecutableJob> { // Input for building swap calldata export interface BuildSwapCalldataInput { // Interface for the swap executor client export interface SwapExecutorClient { // Options for the swap executor export interface SwapExecutorOptions { // Addresses for various swap routers export interface SwapRouterAddresses { // Input for requesting a swap quote export interface SwapQuoteInput { // Input for executing a swap export interface SwapExecuteInput extends SwapQuoteInput { // Result of a swap execution export interface SwapExecuteResult { // Log data extracted from a swap receipt export interface SwapReceiptLog { // Receipt containing details of a swap transaction export interface SwapReceipt { // Common parameters for all job types export interface BaseJobParams { // Parameters specific to limit order jobs export interface LimitOrderParams extends BaseJobParams { // Parameters specific to DCA jobs export interface DCAParams extends BaseJobParams { // Parameters specific to TWAP jobs export interface TWAPParams extends BaseJobParams { // Parameters specific to swap jobs export interface SwapParams extends BaseJobParams { // Base structure for a job export interface BaseJob<TType extends JobType, TParams> { // Result of a job execution attempt export interface ExecuteResult { // Result of a single strategy tick export interface TickResult { // Result of a strategy evaluation export interface EvalResult { // Class for checking price conditions export declare class PriceChecker { // Client for interacting with the automation manager export declare class AutomationManagerClient implements KeeperClient { // Implementation of the keeper client export declare class KeeperClientImpl implements KeeperClient { // Main class for managing and running automation jobs export declare class Keeper { // Price source implementation using GeckoTerminal export declare class GeckoTerminalPriceSource implements PriceSource { // Price source implementation using Swappi export declare class SwappiPriceSource implements PriceSource { // In-memory implementation of the job repository export declare const MemoryJobRepository implements JobRepository { // In-memory implementation of the execution repository export declare const MemoryExecutionRepository implements ExecutionRepository { // Queue for managing job retries export declare class RetryQueue { // Class for enforcing safety rules during execution export declare class SafetyGuard { // Evaluator for DCA strategy jobs export declare class DCAEvaluator implements StrategyEvaluator<DCAJob> { // Evaluator for limit order strategy jobs export declare class LimitOrderEvaluator implements StrategyEvaluator<LimitOrderJob> { // Evaluator for swap strategy jobs export declare class SwapEvaluator implements StrategyEvaluator<SwapJob> { // Evaluator for TWAP strategy jobs export declare class TWAPEvaluator implements StrategyEvaluator<TWAPJob> { // Class responsible for executing swap transactions export declare class SwapExecutor { // Estimates the USD value of an amount export declare function estimateUsdValue(amount: bigint, price: bigint, tokenDecimals?: number): number; // Checks if a DCA job is due for execution export declare function isDCADue(params: DCAParams, nowSec: number, bufferSec?: number): boolean; // Checks if a job has expired export declare function isExpired(job: Job, nowSec: number): boolean; // Converts a decimal number to a scaled bigint export declare function decimalToScaled(value: number, decimals?: number): bigint; // Builds calldata for a swap transaction export declare function buildSwapCalldata(input: BuildSwapCalldataInput): Hex; // Decodes the amount out from a swap receipt export declare function decodeAmountOut(receipt: SwapReceipt, recipient: HexAddress): bigint | undefined; // Returns the transfer event topic hash export declare function transferTopic(): Hex; // Type guard to check if a job is executable export declare function isExecutableJob(job: Job): job is ExecutableJob; // Type for creating a new job from partial data export type NewJobInput = Omit<Job, 'id' | 'status' | 'createdAt' | 'updatedAt' | 'retries'> & { // Union of all available strategy types export type Strategy = LimitOrderStrategy | DCAStrategy | TWAPStrategy | SwapStrategy; // Hexadecimal address type export type HexAddress = HexAddress; // Hexadecimal hash type export type HexHash = HexAddress; // Union of valid job type strings export type JobType = 'limit_order' | 'dca' | 'twap' | 'swap'; // Union of valid job status strings export type JobStatus = 'pending' | 'active' | 'executed' | 'cancelled' | 'failed' | 'expired' | 'paused'; // Comparison direction for triggers export type TriggerDirection = 'gte' | 'lte'; // Type for limit order jobs export declare type LimitOrderJob = BaseJob<'limit_order', LimitOrderParams>; // Type for DCA jobs export declare type DCAJob = BaseJob<'dca', DCAParams>; // Type for TWAP jobs export declare type TWAPJob = BaseJob<'twap', TWAPParams>; // Type for swap jobs export declare type SwapJob = BaseJob<'swap', SwapParams>; // Union of all job types export type Job = LimitOrderJob | DCAJob | TWAPJob | SwapJob; // Union of jobs that are eligible for execution export type ExecutableJob = LimitOrderJob | DCAJob | TWAPJob | SwapJob; // Statuses as they appear on-chain export type OnChainJobStatus = 'active' | 'executed' | 'cancelled' | 'expired';

./db

Usage

import { createSqliteDb, DrizzleJobRepository } from '@cfxdevkit/automation/db'; const db = createSqliteDb('automation.db'); const jobRepo = new DrizzleJobRepository(db);
// Options for the Drizzle execution repository export { DrizzleExecutionRepositoryOptions } // Drizzle-based implementation of the execution repository export { DrizzleExecutionRepository } // Options for the Drizzle job repository export { DrizzleJobRepositoryOptions } // Drizzle-based implementation of the job repository export { DrizzleJobRepository } // SQLite database instance for automation export declare const AutomationSqlite // Helper to create a SQLite database connection export { createSqliteDb } // Helper to initialize the SQLite database schema export { initializeSqliteSchema } // Drizzle table definition for jobs export declare const jobs: import('drizzle-orm/sqlite-core').SQLiteTableWithColumns<{ // Drizzle table definition for executions export declare const executions: import('drizzle-orm/sqlite-core').SQLiteTableWithColumns<{ // Drizzle table definition for worker heartbeats export declare const workerHeartbeat: import('drizzle-orm/sqlite-core').SQLiteTableWithColumns<{ // Drizzle table definition for settings export declare const settings: import('drizzle-orm/sqlite-core').SQLiteTableWithColumns<{
Last updated on