Build crosschain Applications with Aspens Market Stack
This guide shows how to build applications using the Aspens Market Stack (AMS) for crosschain trading. Follow these steps to create applications that let users trade assets across blockchains.
Table of Contents
- Understand the Aspens Market Stack Architecture
- Set Up Your Development Environment
- Connect to an Aspens Market Stack
- Implement Core Trading Functionality
- Build a crosschain Application
- Test and Deploy Your Application
- Access Resources and Support
1. Understand the Aspens Market Stack Architecture
Review AMS Components
An Aspens Market Stack has several components that work together to enable crosschain trading:
- Orderbook: Manage and match trading orders across different chains
- Multi-Chain Contract Manager: Interfaces with smart contracts on multiple blockchains
- Settlement Engine: Ensure secure trade execution
- API Layer: Expose functionality to applications via a well-defined API
Learn the API Communication Flow
Here's the communication flow:
- Your application sends requests to the AMS API layer
- The API layer processes these requests and routes them to the appropriate services
- Services interact with the relevant blockchain networks
- Results flow back through the same path to your application
Explore Available Endpoints
Use these API endpoints in your application:
- Market data (orderbook, trades, prices)
- Account management (balances, deposits, withdrawals)
- Trade execution (create, cancel, query orders)
- Chain status information
2. Set Up Your Development Environment
Check Prerequisites
Before you begin, ensure you have:
- Rust toolchain (install via rustup)
- Git for version control
- Access to an Aspens Market Stack instance (public or self-hosted)
- A wallet private key for trading operations
Install the Aspens SDK
# Clone the SDK repository
git clone https://github.com/aspensprotocol/sdk.git
cd sdk
# Build the SDK and CLI tools
cargo build --release
# The following binaries will be available:
# - target/release/aspens-cli (command-line interface)
# - target/release/aspens-repl (interactive REPL)Available SDK Commands
| Command | Description |
|---|---|
config | Fetch and display the configuration from the server |
deposit <network> <token> <amount> | Deposit tokens to make them available for trading |
withdraw <network> <token> <amount> | Withdraw tokens to a local wallet |
buy-market <market> <amount> | Send a market BUY order |
buy-limit <market> <amount> <price> | Send a limit BUY order |
sell-market <market> <amount> | Send a market SELL order |
sell-limit <market> <amount> <price> | Send a limit SELL order |
cancel-order <market> <side> <order_id> | Cancel an existing order |
balance | Fetch current balances across all chains |
status | Show configuration and connection status |
trader-public-key | Get trader wallet public key and address |
signer-public-key | Get the signer public key(s) for the trading instance |
3. Connect to an Aspens Market Stack
Configure Environment
Create a .env file with your configuration:
# Aspens Market Stack URL (gRPC endpoint)
ASPENS_MARKET_STACK_URL=https://grpc.your-ams-instance.com:50051
# Your trader wallet private key (hex string without 0x prefix)
TRADER_PRIVKEY=your_trader_private_key_hereUsing the CLI
The simplest way to interact with an AMS is using the CLI:
# Check connection and configuration
aspens-cli status
# View server configuration
aspens-cli config
# Get your trader wallet address
aspens-cli trader-public-keyUsing the Interactive REPL
For interactive trading sessions, use the REPL:
aspens-repl
# Inside the REPL:
aspens> help
aspens> status
aspens> balance
aspens> configUsing the Rust Library
Add the aspens crate to your Cargo.toml:
[dependencies]
aspens = { path = "../sdk/aspens" }
tokio = { version = "1", features = ["full"] }
eyre = "0.6"Connect to an AMS in your code:
use aspens::{AspensClient, DirectExecutor};
#[tokio::main]
async fn main() -> eyre::Result<()> {
// Option 1: Use URL from ASPENS_MARKET_STACK_URL in .env
let client = AspensClient::builder().build()?;
// Option 2: Specify URL explicitly
let client = AspensClient::builder()
.with_url("https://grpc.your-ams-instance.com:50051")?
.build()?;
// Option 3: Use a custom .env file
let client = AspensClient::builder()
.with_env_file("/path/to/custom.env")
.build()?;
println!("Connected to: {}", client.stack_url());
Ok(())
}Test the Connection
Verify your connection using the CLI:
# Check connection status
aspens-cli status
# Fetch and display server configuration
aspens-cli config4. Implement Core Trading Functionality
Manage Balances
Check Your Balances
Use the CLI to view balances across all configured chains:
# View all balances
aspens-cli balanceOr in the REPL:
aspens> balanceDeposit and Withdraw Tokens
Deposit Tokens for Trading
Before you can trade, you must deposit tokens to make them available:
# Deposit 1000 USDC from Base Sepolia
aspens-cli deposit base-sepolia USDC 1000
# Deposit 500 USDT from OP Sepolia
aspens-cli deposit op-sepolia USDT 500Withdraw Tokens
Withdraw tokens back to your wallet:
# Withdraw 100 USDC to your wallet on Base Sepolia
aspens-cli withdraw base-sepolia USDC 100Place and Manage Orders
Market Orders
Execute immediately at the best available price:
# Buy 100 USDC worth at market price
aspens-cli buy-market USDC/USDT 100
# Sell 50 USDC at market price
aspens-cli sell-market USDC/USDT 50Limit Orders
Specify the price at which you want to trade:
# Buy 100 USDC at a price of 0.99 USDT per USDC
aspens-cli buy-limit USDC/USDT 100 0.99
# Sell 50 USDC at a price of 1.01 USDT per USDC
aspens-cli sell-limit USDC/USDT 50 1.01Cancel an Order
Cancel a pending order by its ID:
# Cancel a buy order
aspens-cli cancel-order USDC/USDT buy <order_id>
# Cancel a sell order
aspens-cli cancel-order USDC/USDT sell <order_id>Using the Rust Library
For programmatic trading, use the Rust library directly:
use aspens::{AspensClient, DirectExecutor};
use aspens::commands::trading::{deposit, withdraw, send_order, balance};
#[tokio::main]
async fn main() -> eyre::Result<()> {
let client = AspensClient::builder().build()?;
let executor = DirectExecutor;
// Fetch balances
let balances = executor.execute(
balance::get_balance(client.stack_url().to_string())
)?;
println!("Balances: {:?}", balances);
Ok(())
}5. Build a crosschain Application
Application Architecture
When building applications on top of Aspens, you have several integration options:
- CLI Integration: Shell out to
aspens-clifor simple scripts - Rust Library: Use the
aspenscrate directly for Rust applications - gRPC Client: Connect directly to the gRPC API for other languages
Example: Trading Bot in Rust
Here's a complete example of a trading bot using the Aspens SDK:
use aspens::{AspensClient, DirectExecutor};
use aspens::commands::trading::{balance, deposit, send_order};
use aspens::commands::config;
#[tokio::main]
async fn main() -> eyre::Result<()> {
// Initialize client from .env
let client = AspensClient::builder().build()?;
let executor = DirectExecutor;
let stack_url = client.stack_url().to_string();
// Fetch server configuration
let config = executor.execute(
config::get_config(stack_url.clone())
)?;
println!("Connected to stack with {} chains configured",
config.config.as_ref().map(|c| c.chains.len()).unwrap_or(0));
// Check balances
let balances = executor.execute(
balance::get_balance(stack_url.clone())
)?;
println!("Current balances: {:?}", balances);
// Example: Place a limit buy order
// (In practice, you'd implement your trading strategy here)
Ok(())
}Example: CLI Script Integration
For simpler use cases, integrate with shell scripts:
#!/bin/bash
# trading-bot.sh - Simple arbitrage checker
# Check balances
BALANCE=$(aspens-cli balance)
echo "Current balances:"
echo "$BALANCE"
# Place a limit order if conditions are met
if [ "$SHOULD_TRADE" = "true" ]; then
aspens-cli buy-limit USDC/USDT 100 0.995
fiInteractive Trading with REPL
The REPL is ideal for manual trading and testing:
# Start the REPL
aspens-repl
# Example session:
aspens> config # View available markets
aspens> balance # Check your balances
aspens> deposit base-sepolia USDC 1000 # Deposit tokens
aspens> buy-limit USDC/USDT 100 0.99 # Place limit order
aspens> balance # Verify updated balances
aspens> quit # ExitWallet Integration
The SDK handles wallet operations internally using the TRADER_PRIVKEY environment variable. For applications that need to manage multiple wallets:
use aspens::AspensClient;
// Create clients for different wallets by using different .env files
let client_a = AspensClient::builder()
.with_env_file("wallet_a.env")
.build()?;
let client_b = AspensClient::builder()
.with_env_file("wallet_b.env")
.build()?;Each .env file would contain a different TRADER_PRIVKEY:
# wallet_a.env
ASPENS_MARKET_STACK_URL=https://grpc.your-ams-instance.com:50051
TRADER_PRIVKEY=wallet_a_private_key_here
# wallet_b.env
ASPENS_MARKET_STACK_URL=https://grpc.your-ams-instance.com:50051
TRADER_PRIVKEY=wallet_b_private_key_here6. Test and Deploy Your Application
Test on Testnets First
Always test your integration on testnets before deploying to production:
# Configure for testnet
cat > .env << EOF
ASPENS_MARKET_STACK_URL=https://testnet.your-ams-instance.com:50051
TRADER_PRIVKEY=your_testnet_private_key
EOF
# Test connection
aspens-cli status
# Test trading flow
aspens-cli balance
aspens-cli deposit base-sepolia USDC 100
aspens-cli buy-limit USDC/USDT 10 0.99
aspens-cli balanceWrite Integration Tests
For Rust applications, use the built-in test framework:
#[cfg(test)]
mod tests {
use super::*;
use aspens::{AspensClient, DirectExecutor};
#[tokio::test]
async fn test_connection() {
let client = AspensClient::builder()
.with_url("http://localhost:50051")
.unwrap()
.build()
.expect("Failed to build client");
assert!(!client.stack_url().is_empty());
}
#[tokio::test]
async fn test_fetch_config() {
let client = AspensClient::builder().build().unwrap();
let executor = DirectExecutor;
let config = executor.execute(
aspens::commands::config::get_config(client.stack_url().to_string())
);
assert!(config.is_ok());
}
}Run tests with:
cargo testDeploy Your Application
Deploy with proper environment configuration:
# Build release binary
cargo build --release
# Set production environment variables
cat > .env.production << EOF
ASPENS_MARKET_STACK_URL=https://grpc.production-ams.com:50051
TRADER_PRIVKEY=your_production_private_key
EOF
# Run with production config
ASPENS_ENV_FILE=.env.production ./target/release/your-trading-botSecurity Best Practices
- Never commit private keys: Use environment variables or secure vaults
- Use separate wallets for testing and production
- Monitor your balances: Set up alerts for unexpected changes
- Rate limit your requests: Avoid overwhelming the AMS
# Example: Keep private key in secure location
export TRADER_PRIVKEY=$(cat /secure/path/trader.key)
aspens-cli balance7. Access Resources and Support
SDK Documentation
The SDK includes detailed documentation:
- README.md: Getting started guide and command reference
- CLAUDE.md: Architecture guide for developers
- decimals.md: Decimal handling and conversion guide
SDK Command Reference
Quick reference for all available commands:
# Connection & Status
aspens-cli status # Check connection status
aspens-cli config # View server configuration
aspens-cli trader-public-key # Get your wallet address
aspens-cli signer-public-key # Get instance signer keys
# Balance Management
aspens-cli balance # View all balances
aspens-cli deposit <network> <token> <amount> # Deposit tokens
aspens-cli withdraw <network> <token> <amount> # Withdraw tokens
# Trading
aspens-cli buy-market <market> <amount> # Market buy
aspens-cli buy-limit <market> <amount> <price> # Limit buy
aspens-cli sell-market <market> <amount> # Market sell
aspens-cli sell-limit <market> <amount> <price> # Limit sell
aspens-cli cancel-order <market> <side> <id> # Cancel orderJoin the Community
Connect with the Aspens developer community:
- Telegram: https://t.me/aspens_xyz
- Developer Forum: https://github.com/aspensprotocol/feedback/discussions
- Documentation: https://docs.aspens.xyz