Plugin Interface
TypeScript interface definitions for the plugin system.
Implementation: src/plugins/types.ts, src/core/monoid.ts
Plugin
The interface every protocol plugin must implement.
interface Plugin {
metadata: PluginMetadata
defaultConfig: PluginConfig
initialize(context: ExecutionContext): Promise<ProtocolFiber>
}
| Field | Description |
|---|---|
metadata | Static plugin information (id, name, version, etc.) |
defaultConfig | Default configuration values |
initialize | Creates the fiber and registers commands. Called once per plugin load. |
PluginMetadata
interface PluginMetadata {
id: ProtocolId // Unique identifier — must match all commands' protocol field
name: string // Display name (e.g., 'Wormhole')
version: string // Semver (e.g., '0.2.0')
description: string
tags: string[] // e.g., ['bridge', 'cross-chain']
}
Critical: metadata.id is the source of truth for the plugin's identity. It must:
- Match every
Command.protocolfield in the plugin'scommands.ts. - Match the fiber's
idreturned frominitialize. - Be unique across all registered plugins.
The plugin loader enforces fiber.id === plugin.metadata.id at registration time and throws if they differ.
PluginConfig
interface PluginConfig {
enabled: boolean
rpcUrl?: string
// Protocol-specific config fields
[key: string]: unknown
}
Current status: defaultConfig exists but is not injected into initialize() or command execution. Most defaults are unused beyond validation. See Internal: Known Issues.
ProtocolFiber
The runtime representation of a protocol submonoid M_P.
interface ProtocolFiber {
id: ProtocolId
name: string
description?: string
commands: Map<string, Command>
}
| Field | Description |
|---|---|
id | Protocol identifier — must match Plugin.metadata.id |
name | Display name |
commands | Map of command id → Command. Includes the auto-injected protocol identity. |
Do not manipulate commands directly. Use addCommandToFiber which validates scope and protocol before adding.
createProtocolFiber
Creates a new ProtocolFiber with the protocol-specific identity element automatically injected.
function createProtocolFiber(
id: ProtocolId,
name: string,
description?: string
): ProtocolFiber
Implementation: src/core/monoid.ts:128
The injected identity command has:
{
id: 'identity',
scope: 'G_p',
protocol: id,
description: `Identity operation for ${name}`,
run: async <T>(args: T) => ({ success: true, value: args })
}
This ensures each M_P is a proper submonoid (not just a semigroup).
addCommandToFiber
Validates and registers a command into a fiber's command map.
function addCommandToFiber(fiber: ProtocolFiber, command: Command): void
Throws if:
command.scope !== 'G_p'command.protocol !== fiber.id
Implementation: src/core/monoid.ts:117
HandlerMap
Optional — for plugins with transaction signing flows.
type HandlerMap = Record<string, Handler>
type Handler = (
result: CommandResult<unknown>,
context: ExecutionContext,
walletClient: WalletClient
) => Promise<HandlerResult>
interface HandlerResult {
success: boolean
pipelineOutput?: PipelineOutput
}
Handlers are registered separately from commands and invoked by the CLI after command.run() returns a transaction payload. The handler receives the wallet client and is responsible for signing and broadcasting.
Known issue: The current handler dispatch path has a protocol mismatch risk for alias commands. See Internal: Known Issues.
Plugin Registration
Plugins are exported from src/plugins/index.ts and loaded by the plugin loader:
// src/plugins/index.ts
export const plugins: Plugin[] = [
oneinchPlugin,
lifiPlugin,
wormholePlugin,
stargatePlugin,
coinpaprikaPlugin,
]
Plugin loader: src/plugins/plugin-loader.ts
The loader:
- Calls
plugin.initialize(context)for each plugin. - Validates
fiber.id === plugin.metadata.id. - Registers the fiber into the global command registry.
Current limitation: The plugin loader is a global singleton. New tabs repeatedly call loadPlugin() into the same loader without guarding for already-loaded plugins. Initialization may repeat and overwrite the same registry entries. See Internal: Known Issues.