Skip to content

First Swap

This example mirrors the runtime flow used in examples/simple-swap.

import {
ConsoleLogger,
DeFiRuntime,
type SpendingLimitRule,
} from '@stendar/core';
import { JupiterProvider } from '@stendar/provider-jupiter';
import { NATIVE_SOL_MINT, USDC_MINT, SolanaChainAdapter } from '@stendar/solana';
import { RawKeypairAdapter } from '@stendar/wallet-core';
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 policy: SpendingLimitRule = {
id: 'daily-limit',
type: 'spending_limit',
enabled: true,
maxDaily: 100,
currency: 'USD',
};
const runtime = new DeFiRuntime({
chains: [new SolanaChainAdapter({ rpcUrl })],
providers: [new JupiterProvider()],
wallet: new RawKeypairAdapter(privateKey),
policies: [policy],
logger: new ConsoleLogger({ component: 'first-swap' }),
});
runtime.on('policy:decision', (decision, intent) => {
console.log('policy', decision.decision, intent.type);
});
await runtime.start();
try {
const result = await runtime.executeSwap({
inputToken: NATIVE_SOL_MINT,
outputToken: USDC_MINT,
amount: 10_000_000n,
amountUsd: 1,
slippageBps: 50,
dryRun: true,
});
console.log(result.status);
} finally {
await runtime.stop();
}
  1. Runtime resolves provider and quote
  2. Policy rules evaluate the intent
  3. Chain adapter simulates transaction
  4. Because dryRun is true, execution returns after simulation

Next: wire this into a multi-step flow with First strategy.