Skip to main content

Mastra Quick Start

Build a working DeFi agent in 5 minutes using Mastra's workflow system and ZeroQuant.

Why Mastra?

Mastra provides:

  • Pre-built workflows - Common DeFi operations as reusable workflows
  • Agent templates - Trading, Yield, and Portfolio agents ready to customize
  • State management - Persistent state across agent sessions
  • Type safety - Full TypeScript support with Zod validation

Prerequisites

  • Node.js 18+
  • An Ethereum wallet with testnet ETH (Sepolia)
  • OpenAI API key (or any LLM provider)

Installation

npm install @zeroquant/sdk @zeroquant/mastra @mastra/core ethers

Step 1: Set Up Environment

Create a .env file:

OPENAI_API_KEY=sk-...
PRIVATE_KEY=0x...
RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
FACTORY_ADDRESS=0x...
PERMISSION_MANAGER_ADDRESS=0x...

Step 2: Initialize the Toolkit

import { ethers } from 'ethers';
import { ZeroQuantClient } from '@zeroquant/sdk';
import { ZeroQuantToolkit } from '@zeroquant/mastra';

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);

const client = new ZeroQuantClient(provider, {
factoryAddress: process.env.FACTORY_ADDRESS!,
permissionManagerAddress: process.env.PERMISSION_MANAGER_ADDRESS!,
});
await client.connect(signer);

const toolkit = new ZeroQuantToolkit({ client });

Step 3: Use Pre-built Tools

// Get all available tools
const tools = toolkit.getTools();

// Tools include:
// - createVault: Deploy a new vault
// - connectVault: Connect to existing vault
// - getBalance: Check vault balance
// - executeSwap: Execute token swaps
// - executeBatch: Batch multiple operations

Step 4: Use Workflows

Mastra provides pre-built workflows for common operations:

Safe Swap Workflow

Executes a swap with safety checks:

import { SafeSwapWorkflow } from '@zeroquant/mastra';

const workflow = new SafeSwapWorkflow({
client,
vaultAddress: '0x...',
tokenIn: '0x...', // WETH
tokenOut: '0x...', // USDC
amountIn: ethers.parseEther('1.0'),
maxSlippageBps: 50, // 0.5%
});

// Workflow steps:
// 1. Check vault has sufficient balance
// 2. Get price quote
// 3. Calculate minimum output with slippage
// 4. Execute swap
// 5. Verify output received

const result = await workflow.execute();
console.log('Swap completed:', result);

Vault Creation Workflow

Creates and optionally funds a new vault:

import { VaultCreationWorkflow } from '@zeroquant/mastra';

const workflow = new VaultCreationWorkflow({
client,
salt: 42,
initialFundingEth: '0.1', // Optional: fund with ETH
});

const result = await workflow.execute();
console.log('Vault created at:', result.vaultAddress);

Step 5: Build a Trading Agent

Use the pre-built Trading Agent template:

import { TradingAgent } from '@zeroquant/mastra';
import { ChatOpenAI } from '@langchain/openai';

const llm = new ChatOpenAI({ modelName: 'gpt-4', temperature: 0 });

const agent = new TradingAgent({
client,
llm,
vaultAddress: '0x...',
config: {
maxSlippageBps: 100, // 1% max slippage
maxTradeSize: '10', // Max 10 ETH per trade
allowedTokens: ['WETH', 'USDC', 'DAI'],
},
});

// The agent can now:
// - Analyze market conditions
// - Execute trades within limits
// - Track performance

const result = await agent.chat('Buy 0.5 ETH worth of USDC');
console.log(result);

Complete Example

import { ethers } from 'ethers';
import { ZeroQuantClient } from '@zeroquant/sdk';
import { ZeroQuantToolkit, TradingAgent, VaultCreationWorkflow } from '@zeroquant/mastra';
import { ChatOpenAI } from '@langchain/openai';
import 'dotenv/config';

async function main() {
// Setup
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);

const client = new ZeroQuantClient(provider, {
factoryAddress: process.env.FACTORY_ADDRESS!,
permissionManagerAddress: process.env.PERMISSION_MANAGER_ADDRESS!,
});
await client.connect(signer);

// Create a vault using workflow
const createWorkflow = new VaultCreationWorkflow({
client,
salt: Date.now(), // Unique salt
});

console.log('Creating vault...');
const { vaultAddress } = await createWorkflow.execute();
console.log('Vault created at:', vaultAddress);

// Initialize trading agent
const llm = new ChatOpenAI({ modelName: 'gpt-4', temperature: 0 });

const agent = new TradingAgent({
client,
llm,
vaultAddress,
config: {
maxSlippageBps: 100,
maxTradeSize: '1',
allowedTokens: ['WETH', 'USDC'],
},
});

// Interactive trading session
console.log('\nTrading Agent Ready!\n');
console.log('Try commands like:');
console.log(' - "What is my vault balance?"');
console.log(' - "Swap 0.1 ETH for USDC"');
console.log(' - "Show my recent trades"\n');

const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

const chat = async () => {
rl.question('You: ', async (input: string) => {
if (input.toLowerCase() === 'exit') {
rl.close();
return;
}

const response = await agent.chat(input);
console.log(`\nAgent: ${response}\n`);
chat();
});
};

chat();
}

main().catch(console.error);

Available Agent Templates

Trading Agent

Executes trades based on user commands with safety limits.

import { TradingAgent } from '@zeroquant/mastra';

Yield Agent

Monitors and optimizes yield across protocols.

import { YieldAgent } from '@zeroquant/mastra';

const agent = new YieldAgent({
client,
llm,
vaultAddress,
config: {
minApy: 5, // Minimum 5% APY
rebalanceThreshold: 2, // Rebalance if APY diff > 2%
},
});

Portfolio Agent

Manages portfolio allocation and rebalancing.

import { PortfolioAgent } from '@zeroquant/mastra';

const agent = new PortfolioAgent({
client,
llm,
vaultAddress,
targetAllocation: {
'WETH': 50, // 50% ETH
'USDC': 30, // 30% USDC
'DAI': 20, // 20% DAI
},
});

State Management

Mastra includes persistent state management:

import { VaultStateManager } from '@zeroquant/mastra';

const stateManager = new VaultStateManager();

// Track vault state
stateManager.setVault(vaultAddress, {
balance: '1.5',
lastActivity: Date.now(),
totalTrades: 42,
});

// Retrieve state
const state = stateManager.getVault(vaultAddress);

What's Next?


Need help? Join our Discord or check the Mastra docs.