Skip to content

First Strategy

StrategyEngine runs YAML-defined step graphs on top of DeFiRuntime.

name: first-strategy
chain: solana-mainnet
onError: pause
steps:
- id: wait-window
type: watch
condition:
type: time
afterTimestamp: 1700000000
pollIntervalMs: 5000
- id: buy-sol
type: action
action:
type: swap
inputToken: USDC
outputToken: SOL
amount: "1000000"
amountUsd: 1
slippageBps: 50
import {
ConsoleLogger,
DeFiRuntime,
StrategyEngine,
TypedEmitter,
parseStrategyFromYaml,
type RuntimeEvents,
} from '@stendar/core';
import { JupiterProvider } from '@stendar/provider-jupiter';
import { SolanaChainAdapter } from '@stendar/solana';
import { RawKeypairAdapter } from '@stendar/wallet-core';
const strategyYamlString = `
name: first-strategy
chain: solana-mainnet
onError: pause
steps:
- id: wait-window
type: watch
condition:
type: time
afterTimestamp: 1700000000
pollIntervalMs: 5000
- id: buy-sol
type: action
action:
type: swap
inputToken: USDC
outputToken: SOL
amount: "1000000"
amountUsd: 1
slippageBps: 50
`;
process.loadEnvFile?.();
const rpcUrl = process.env.SOLANA_RPC_URL;
const privateKey = process.env.WALLET_PRIVATE_KEY;
if (!rpcUrl || !privateKey) {
throw new Error('Missing SOLANA_RPC_URL or WALLET_PRIVATE_KEY');
}
const runtime = new DeFiRuntime({
chains: [new SolanaChainAdapter({ rpcUrl })],
providers: [new JupiterProvider()],
wallet: new RawKeypairAdapter(privateKey),
dryRun: true,
logger: new ConsoleLogger({ component: 'first-strategy' }),
});
const events = new TypedEmitter<RuntimeEvents>();
// Strategy events (strategy:*) fire on this emitter.
// Runtime events (tx:*, policy:*) fire on runtime.on() instead.
events.on('strategy:step_started', ({ stepId }) => console.log('step', stepId));
events.on('strategy:completed', ({ executionId }) => console.log('done', executionId));
await runtime.start();
try {
const strategy = parseStrategyFromYaml(strategyYamlString);
const engine = new StrategyEngine(runtime, events, new ConsoleLogger({ component: 'engine' }));
// Wait for strategy completion so runtime.stop() in finally does not race engine execution.
const done = new Promise<void>((resolve) => events.on('strategy:completed', () => resolve()));
const executionId = await engine.start(strategy);
console.log('started', executionId);
await done;
} finally {
await runtime.stop();
}

For strategy structure and step semantics, continue to Strategies concept.