Skip to main content
The Ember Plugin System has the following architecture:
onchain-actions-plugins/
└── registry/
    ├── src/
    │   ├── core/              # Type definitions, interfaces, and schemas for plugin development.
    │   ├── aave-lending-plugin/   #  Complete AAVE V3 lending plugin serving as a development example.
    │   ├── registry.ts        # Plugin registration and discovery system.
    │   ├── chainConfig.ts     # Chain configuration utilities
    │   └── index.ts           # Main registry initialization
    ├── package.json
    ├── tsconfig.json
    └── tsup.config.ts
The core framework provides the following components:
  • actions: Action type definitions and interfaces for all plugin types
  • queries: Query type definitions for retrieving protocol data
  • schemas: Zod validation schemas for requests and responses
  • pluginType.ts: Core plugin type definitions
  • index.ts: Main exports for plugin development
These components work together to create a type-safe plugin system: index.ts defines the foundational EmberPlugin interface, while pluginType.ts defines the plugin types (lending, liquidity, swap, perpetuals) and maps each type to its available actions and queries. The actions directory provides the executable operations (supply, borrow, swap, etc.) with their callback signatures, while queries enable data retrieval without transactions. All inputs and outputs are validated through schemas, ensuring type safety and data consistency across the system.

Ember Plugin Interface

The framework defines an EmberPlugin<Type> interface, and each plugin must implement this interface:
interface EmberPlugin<Type extends PluginType> {
  id?: string; // Unique identifier
  type: Type; // Plugin type (lending, liquidity, swap, perpetuals)
  name: string; // Human-readable name
  description?: string; // Optional description
  website?: string; // Official website
  x?: string; // Twitter/X handle
  actions: ActionDefinition<AvailableActions[Type]>[]; // Available actions for this plugin type
  queries: AvailableQueries[Type]; // Data queries for this plugin type
}
The system supports four main plugin types:
  • Lending: Supply, borrow, repay, and withdraw operations
  • liquidity: Add and remove liquidity from pools
  • swap: Token exchange operations
  • perpetuals: Long, short, and close perpetual positions

Actions

Each plugin type defines specific actions it can execute. For example, lending plugins can do lending-supply, lending-borrow, lending-repay, and lending-withdraw. Each action has callback functions that define its request and response.
interface ActionDefinition<T extends Action> {
  name: string; // Unique action name
  type: T; // Action type
  callback: ActionCallback<T>; // Implementation function
  inputTokens: () => Promise<TokenSet[]>; // Supported input tokens
  outputTokens?: () => Promise<TokenSet[]>; // Optional output tokens
}
Input Tokens: The tokens that the user needs to execute this action. Token sets are organized by chain ID, and each action defines its own input/output token mapping. Output Tokens: The tokens that the user receives through this action (optional field). Note that the function doesn’t take all tokens, just transforms one of the supported input tokens into one of the supported output tokens.

Queries

Each plugin type can define queries to retrieve protocol data without executing transactions:
// Query interfaces by plugin type
type AvailableQueries = {
  lending: { getPositions: LendingGetPositions };
  liquidity: { getWalletPositions: LiquidityGetWalletPositions; getPools: LiquidityGetPools };
  swap: Record<string, never> | undefined; // No queries supported
  perpetuals: {
    getMarkets: PerpetualsGetMarkets;
    getPositions: PerpetualsGetPositions;
    getOrders: PerpetualsGetOrders;
  };
};
Query examples:
  • Lending: Get user positions, health factors, and borrowing capacity
  • Liquidity: Get wallet LP positions and available pools
  • Perpetuals: Get markets, active positions, and pending orders
  • Swap: No queries (stateless operations)

Schema Architecture

The schema system provides comprehensive type safety with Zod validation: Core Schemas (schemas/core.ts):
  • TokenSchema: Complete token metadata, including native token handling
  • TransactionPlanSchema: Standardized transaction format for all chains
  • FeeBreakdownSchema: Service fees and slippage cost structure
  • BalanceSchema: User wallet balance representation
Action-Specific Schemas:
  • Lending (schemas/lending.ts): Supply, borrow, repay, and withdraw operations with comprehensive position tracking
  • Liquidity (schemas/liquidity.ts): Advanced liquidity provision with discriminated unions for full/limited range positions
  • Swap (schemas/swap.ts): Token exchange with slippage tolerance and price tracking
  • Perpetuals (schemas/perpetuals.ts): Integration with GMX SDK for complex derivatives trading

Plugin Registry

The registry (registry.ts) manages plugin discovery and registration. You can initialize a registry using initializePublicRegistry().Use registerDeferredPlugin() for plugin initialization:
// For plugins that need async setup (network calls, contract loading, etc.)
registry.registerDeferredPlugin(
  getAaveEmberPlugin({
    chainId: 42161,
    rpcUrl: 'https://arb1.arbitrum.io/rpc',
    wrappedNativeToken: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
  }),
);
I