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:
- A development environment with Node.js (v14+), Python (v3.8+), or Go (v1.16+)
- Git for version control
- gRPC tools for your preferred language
- Access to an Aspens Market Stack instance (public or self-hosted)
3. Connect to an Aspens Market Stack¶
Configure Connection Parameters¶
Create a configuration file for your application:
{
"api": {
"endpoint": "api.aspens-stack.example.com:50051",
"useTls": true,
"timeout": 5000
},
"credentials": {
"apiKey": "your-api-key"
}
}
Establish a Connection¶
Node.js Example:¶
const grpc = require('@grpc/grpc-js');
const { AspensClient } = require('./src/aspens_grpc_pb');
function createClient(config) {
let credentials;
if (config.api.useTls) {
credentials = grpc.credentials.createSsl();
} else {
credentials = grpc.credentials.createInsecure();
}
const client = new AspensClient(
config.api.endpoint,
credentials
);
// Add API key metadata
const metadata = new grpc.Metadata();
metadata.add('x-api-key', config.credentials.apiKey);
return { client, metadata };
}
const { client, metadata } = createClient(require('./config.json'));
Python Example:¶
import grpc
from src import aspens_pb2_grpc
def create_client(config):
if config['api']['useTls']:
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(config['api']['endpoint'], credentials)
else:
channel = grpc.insecure_channel(config['api']['endpoint'])
client = aspens_pb2_grpc.AspensStub(channel)
# Create metadata for API key
metadata = [('x-api-key', config['credentials']['apiKey'])]
return client, metadata
# Load config and create client
import json
with open('config.json') as f:
config = json.load(f)
client, metadata = create_client(config)
Test the Connection¶
Verify your connection by requesting basic market data:
// Node.js
const { MarketRequest } = require('./src/aspens_pb');
function testConnection() {
const request = new MarketRequest();
request.setMarketId('USDT:USDT');
client.getMarketInfo(request, metadata, (err, response) => {
if (err) {
console.error('Connection error:', err);
return;
}
console.log('Connected successfully!');
console.log('Market info:', response.toObject());
});
}
testConnection();
4. Implement Core Trading Functionality¶
Fetch Market Data¶
Retrieve the Orderbook:¶
// Node.js
const { OrderbookRequest } = require('./src/aspens_pb');
function getOrderbook(marketId, depth = 10) {
return new Promise((resolve, reject) => {
const request = new OrderbookRequest();
request.setMarketId(marketId);
request.setDepth(depth);
client.getOrderbook(request, metadata, (err, response) => {
if (err) {
reject(err);
return;
}
resolve({
bids: response.getBidsList().map(order => ({
price: order.getPrice(),
quantity: order.getQuantity()
})),
asks: response.getAsksList().map(order => ({
price: order.getPrice(),
quantity: order.getQuantity()
}))
});
});
});
}
Manage User Balances¶
Get User Balances:¶
# Python
from src import aspens_pb2
def get_balances(user_id):
request = aspens_pb2.BalanceRequest()
request.user_id = user_id
response = client.GetBalances(request, metadata=metadata)
balances = {}
for balance in response.balances:
balances[balance.token] = {
'available': balance.available,
'locked': balance.locked
}
return balances
Place and Manage Orders¶
Create a Limit Order:¶
// Node.js
const { OrderRequest, OrderType, OrderSide } = require('./src/aspens_pb');
function placeLimitOrder(marketId, userId, side, price, quantity) {
return new Promise((resolve, reject) => {
const request = new OrderRequest();
request.setMarketId(marketId);
request.setUserId(userId);
request.setOrderType(OrderType.LIMIT);
request.setOrderSide(side === 'buy' ? OrderSide.BUY : OrderSide.SELL);
request.setPrice(price);
request.setQuantity(quantity);
client.placeOrder(request, metadata, (err, response) => {
if (err) {
reject(err);
return;
}
resolve({
orderId: response.getOrderId(),
status: response.getStatus()
});
});
});
}
Cancel an Order:¶
# Python
from src import aspens_pb2
def cancel_order(order_id, user_id):
request = aspens_pb2.CancelOrderRequest()
request.order_id = order_id
request.user_id = user_id
response = client.CancelOrder(request, metadata=metadata)
return {
'success': response.success,
'message': response.message
}
5. Build a crosschain Application¶
Create a crosschain Trading Dashboard¶
Build a web application that lets users trade USDT on Ethereum and USDC on Arbitrum.
Organize Backend Structure:¶
src/
├── api/
│ ├── routes.js # Express routes
│ └── controllers.js # Business logic
├── services/
│ ├── aspens.js # AMS client wrapper
│ ├── ethereum.js # Ethereum wallet integration
│ └── arbitrum.js # Arbitrum wallet integration
├── utils/
│ └── validation.js # Input validation
└── server.js # Main entry point
Develop Frontend Components:¶
src/
├── components/
│ ├── Orderbook.jsx # Displays orderbook data
│ ├── TradeForm.jsx # Order entry form
│ ├── WalletConnect.jsx # Wallet connection UI
│ └── TradeHistory.jsx # Shows recent trades
├── services/
│ └── api.js # API client for backend
└── App.jsx # Main application
Integrate Wallets¶
Implement wallet connections for both chains:
// ethereum.js
const { ethers } = require('ethers');
async function connectEthereumWallet() {
if (window.ethereum) {
try {
// Request account access
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
return {
address: accounts[0],
provider,
signer
};
} catch (error) {
throw new Error(`Ethereum wallet connection failed: ${error.message}`);
}
} else {
throw new Error('Please install MetaMask to use this feature');
}
}
Create Order Submission Functionality¶
Create a controller that handles trade submissions:
// controllers.js
const aspensService = require('../services/aspens');
async function submitTrade(req, res) {
try {
const { marketId, side, price, quantity, userId } = req.body;
// Validate inputs
if (!marketId || !side || !price || !quantity || !userId) {
return res.status(400).json({
success: false,
message: 'Missing required parameters'
});
}
// Submit order to Aspens Market Stack
const orderResult = await aspensService.placeLimitOrder(
marketId,
userId,
side,
price,
quantity
);
return res.json({
success: true,
data: orderResult
});
} catch (error) {
console.error('Trade submission error:', error);
return res.status(500).json({
success: false,
message: error.message || 'Failed to submit trade'
});
}
}
Add Real-Time Updates with WebSockets¶
Implement real-time orderbook updates:
// aspens.js
const WebSocket = require('ws');
function subscribeToOrderbook(marketId, callback) {
const ws = new WebSocket('wss://api.aspens-stack.example.com/ws');
ws.on('open', () => {
ws.send(JSON.stringify({
action: 'subscribe',
channel: 'orderbook',
marketId
}));
});
ws.on('message', (data) => {
try {
const parsedData = JSON.parse(data);
callback(null, parsedData);
} catch (error) {
callback(error);
}
});
ws.on('error', (error) => {
callback(error);
});
return {
unsubscribe: () => {
ws.close();
}
};
}
6. Test and Deploy Your Application¶
Write Unit Tests¶
Create tests for your API integration:
// test/aspens.test.js
const { expect } = require('chai');
const sinon = require('sinon');
const aspensService = require('../src/services/aspens');
describe('Aspens Market Stack Integration', () => {
it('should fetch orderbook data successfully', async () => {
// Mock response data
const mockOrderbook = {
bids: [{ price: '0.995', quantity: '1000' }],
asks: [{ price: '1.005', quantity: '500' }]
};
// Create a stub for the API call
const stub = sinon.stub(aspensService.client, 'getOrderbook')
.callsFake((request, metadata, callback) => {
callback(null, {
getBidsList: () => mockOrderbook.bids.map(bid => ({
getPrice: () => bid.price,
getQuantity: () => bid.quantity
})),
getAsksList: () => mockOrderbook.asks.map(ask => ({
getPrice: () => ask.price,
getQuantity: () => ask.quantity
}))
});
});
// Call the service method
const result = await aspensService.getOrderbook('USDT:USDT');
// Verify the result
expect(result.bids).to.have.lengthOf(1);
expect(result.asks).to.have.lengthOf(1);
expect(result.bids[0].price).to.equal('0.995');
// Restore the stub
stub.restore();
});
});
Run Integration Tests¶
Test with a sandbox AMS instance:
// Set up environment for testing
process.env.ASPENS_API_ENDPOINT = 'sandbox.aspens-stack.example.com:50051';
process.env.ASPENS_API_KEY = 'test-api-key';
// Run your integration tests
// ...
Deploy Your Application¶
Deploy your application with proper environment configuration:
# Example deployment script for a Node.js application
npm run build
# Set production environment variables
export NODE_ENV=production
export ASPENS_API_ENDPOINT=api.aspens-stack.example.com:50051
export ASPENS_API_KEY=your-production-api-key
# Start the application
npm start
Develop Multi-Chain Wallet Management¶
Help users manage assets across chains:
async function suggestCrossChainOpportunities(userId) {
// Get balances on both chains
const balances = await aspensService.getBalances(userId);
// Get current market rates
const market = await aspensService.getMarketInfo('USDT:USDT');
// Calculate potential arbitrage opportunities
const opportunities = [];
if (balances['USDT-ethereum'] > 100 && market.lastPrice < 0.98) {
opportunities.push({
type: 'buy',
from: 'Ethereum',
to: 'Arbitrum',
potentialProfit: `${((1/market.lastPrice - 1) * 100).toFixed(2)}%`
});
}
if (balances['USDT-arbitrum'] > 100 && market.lastPrice > 1.02) {
opportunities.push({
type: 'sell',
from: 'Arbitrum',
to: 'Ethereum',
potentialProfit: `${((market.lastPrice - 1) * 100).toFixed(2)}%`
});
}
return opportunities;
}
7. Access Resources and Support¶
Read API Reference Documentation¶
API documentation is available at: - https://docs.aspens.xyz/api-reference
Explore Sample Applications¶
Check out complete example applications: - crosschain Trading Dashboard - Arbitrage Bot - Mobile Wallet Integration
Join the Community¶
Connect with the Aspens developer community: - Telegram: https://t.me/aspens_xyz - Developer Forum: https://github.com/aspensprotocol/feedback/discussions