Skip to content

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

  1. Understand the Aspens Market Stack Architecture
  2. Set Up Your Development Environment
  3. Connect to an Aspens Market Stack
  4. Implement Core Trading Functionality
  5. Build a crosschain Application
  6. Test and Deploy Your Application
  7. 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:

  1. Your application sends requests to the AMS API layer
  2. The API layer processes these requests and routes them to the appropriate services
  3. Services interact with the relevant blockchain networks
  4. 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

CommandDescription
configFetch 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
balanceFetch current balances across all chains
statusShow configuration and connection status
trader-public-keyGet trader wallet public key and address
signer-public-keyGet 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_here

Using 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-key

Using the Interactive REPL

For interactive trading sessions, use the REPL:

aspens-repl
 
# Inside the REPL:
aspens> help
aspens> status
aspens> balance
aspens> config

Using 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 config

4. Implement Core Trading Functionality

Manage Balances

Check Your Balances

Use the CLI to view balances across all configured chains:

# View all balances
aspens-cli balance

Or in the REPL:

aspens> balance

Deposit 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 500

Withdraw Tokens

Withdraw tokens back to your wallet:

# Withdraw 100 USDC to your wallet on Base Sepolia
aspens-cli withdraw base-sepolia USDC 100

Place 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 50

Limit 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.01

Cancel 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:

  1. CLI Integration: Shell out to aspens-cli for simple scripts
  2. Rust Library: Use the aspens crate directly for Rust applications
  3. 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
fi

Interactive 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                             # Exit

Wallet 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_here

6. 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 balance

Write 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 test

Deploy 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-bot

Security Best Practices

  1. Never commit private keys: Use environment variables or secure vaults
  2. Use separate wallets for testing and production
  3. Monitor your balances: Set up alerts for unexpected changes
  4. 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 balance

7. 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 order

Join the Community

Connect with the Aspens developer community: