@0xmonaco/core
v0.4.1
Published
⚠️ **EARLY DEVELOPMENT WARNING** ⚠️
Readme
Monaco Core SDK
⚠️ EARLY DEVELOPMENT WARNING ⚠️
This package is currently in early development.
Breaking changes are expected and may occur without notice. This version is intended for:
- Early adopters and testing
- Development and experimentation
- Feedback collection
Core SDK implementation for interacting with Monaco Protocol. This SDK provides a comprehensive implementation with Authentication, Vault, Trading, Market, and Profile APIs, featuring JWT authentication and secure API Gateway integration.
Installation
npm install @0xmonaco/coreFeatures
🔐 Authentication
- JWT-based Authentication: Secure token-based authentication
- Wallet Signature Verification: EIP-712 signature-based login
- Token Refresh: Automatic token refresh and management
- Session Management: Secure session handling
🏦 Vault Operations
- Token Approvals: ERC20 token approvals for vault usage
- Deposits: Secure token deposits with signature validation
- Withdrawals: Token withdrawals with cryptographic validation
- Balance Queries: Real-time vault balance tracking
📈 Trading Operations
- Order Types: Limit and Market orders
- Order Management: Place, replace, and cancel orders
- Order Queries: Paginated orders, order history, and individual order details
- Real-time Updates: WebSocket support for live order updates
📊 Market Data
- Trading Pairs: Complete trading pair metadata
- Market Information: Fees, tick sizes, order limits
- Pair Discovery: Search and filter available markets
👤 Profile Management
- User Profiles: Account information and settings
- Sub-accounts: Multi-account management
- Balance Tracking: Cross-platform balance monitoring
🔐 Security Features
- JWT Authentication: Secure API access with token validation
- EIP-712 Signatures: Type-safe, structured data signing for authentication
- API Gateway Integration: Secure communication with Monaco backend
- TLS Encryption: Secure API communications
Test Setup
Before running tests, ensure you have:
A running hardhat node with the Monaco Protocol contracts deployed:
# In the contracts package cd ../contracts pnpm hardhat node # Start a local hardhat node pnpm hardhat deploy --network localhost # Deploy contractsCreate a
.env.testfile in the tests directory:# Create the file cd packages/core/tests touch .env.test # Add the following content to .env.test: echo 'TEST_PRIVATE_KEY=0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' > .env.testReplace the example private key in
.env.testwith your actual test account private key:- The private key must be a 0x-prefixed 64-character hex string
- The account must have enough ETH on the local hardhat network for transactions
- Never commit real private keys to version control
Verify your setup:
# Make sure you're in the core package directory cd packages/core # Check if .env.test exists and has the correct format cat tests/.env.test # Should show: TEST_PRIVATE_KEY=0x... # Run the tests pnpm test
If you see an error about TEST_PRIVATE_KEY not being set:
- Double check that
.env.testexists inpackages/core/testsdirectory - Make sure the private key format is correct (0x-prefixed, 64 characters)
- Try running the tests with the environment variable directly:
TEST_PRIVATE_KEY=0x1234... pnpm test
Network Support
The SDK supports both Sei mainnet (pacific-1) and testnet (atlantic-2) networks. You configure the network by providing the network and seiRpcUrl parameters:
import { MonacoSDK } from "@0xmonaco/core";
// Testnet configuration
const testnetSdk = new MonacoSDK({
walletClient,
network: "testnet",
seiRpcUrl: "https://evm-rpc-testnet.sei-apis.com" // Atlantic-2 testnet
});
// Mainnet configuration
const mainnetSdk = new MonacoSDK({
walletClient,
network: "mainnet",
seiRpcUrl: "https://evm-rpc.sei-apis.com" // Pacific-1 mainnet
});Quick Start
import { MonacoSDK } from "@0xmonaco/core";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
// Initialize the SDK with wallet client
const account = privateKeyToAccount("0x...");
const walletClient = createWalletClient({
account,
chain: sei, // or seiTestnet
transport: http("https://evm-rpc.sei-apis.com") // or https://evm-rpc-testnet.sei-apis.com for testnet
});
const monaco = new MonacoSDK({
walletClient,
network: "mainnet", // or "testnet"
seiRpcUrl: "https://evm-rpc.sei-apis.com" // or https://evm-rpc-testnet.sei-apis.com for testnet
});
// Authentication
async function authExample() {
// Login with client ID and auto-connect authenticated WebSocket channels (Orders)
const authState = await monaco.login("your-client-id", { connectWebSocket: true });
console.log("Authenticated:", authState.user);
console.log("Tokens:", {
accessToken: authState.accessToken,
refreshToken: authState.refreshToken, // Use this for revokeToken()
});
// Authenticated WebSocket channels are now connected - start receiving real-time updates
// Currently this includes: Orders (personal order updates)
monaco.websocket.orders.subscribeToOrderEvents("BTC/USDC", "SPOT", (event) => {
console.log("Order event:", event.eventType);
});
// Check authentication status
console.log("Is authenticated:", monaco.isAuthenticated());
// Logout (revokes the refresh token and disconnects authenticated WebSockets)
await monaco.logout();
// Or manually revoke the token
// ✅ CORRECT: Use authState.refreshToken
await monaco.auth.revokeToken(authState.refreshToken);
}
// Market Data
async function marketExample() {
// Get all trading pairs
const pairs = await monaco.market.getTradingPairs();
console.log("Available pairs:", pairs.length);
// Get specific trading pair
const btcPair = await monaco.market.getTradingPairBySymbol("BTC/USDC");
console.log("BTC pair:", btcPair?.symbol, btcPair?.maker_fee_bps);
}
// Vault Operations
async function vaultExample() {
// Check vault balance
const balance = await monaco.vault.getBalance("0x..."); // token address
console.log("Vault balance:", balance.formatted, balance.symbol);
// Approve vault to spend tokens
const approval = await monaco.vault.approve("0x...", parseEther("1000"));
console.log("Approval transaction:", approval.hash);
// Deposit tokens
const result = await monaco.vault.deposit("0x...", parseEther("100"));
console.log("Deposit transaction:", result.hash);
// Withdraw tokens
const withdrawal = await monaco.vault.withdraw("0x...", parseEther("50"));
console.log("Withdrawal transaction:", withdrawal.hash);
}
// Trading Operations
async function tradingExample() {
// Place a limit order
const order = await monaco.trading.placeLimitOrder(
"BTC/USDC", // market
"BUY", // side
"0.001", // quantity
"50000" // price
);
console.log("Order placed:", order.order_id);
// Place a limit order with IOC (Immediate or Cancel)
const iocOrder = await monaco.trading.placeLimitOrder(
"BTC/USDC",
"BUY",
"0.001",
"50000",
{ timeInForce: "IOC" } // Execute immediately or cancel
);
console.log("IOC order placed:", iocOrder.order_id);
// Place a market order
const marketOrder = await monaco.trading.placeMarketOrder(
"BTC/USDC",
"SELL",
"0.001"
);
console.log("Market order placed:", marketOrder.order_id);
// Place a market order with FOK (Fill or Kill)
const fokOrder = await monaco.trading.placeMarketOrder(
"BTC/USDC",
"BUY",
"0.001",
{ timeInForce: "FOK" } // Must fill completely or cancel
);
console.log("FOK order placed:", fokOrder.order_id);
// Get paginated orders
const orders = await monaco.trading.getPaginatedOrders({
status: "PENDING",
trading_pair: "BTC/USDC",
page: 1,
page_size: 10
});
console.log("Orders:", orders.data.length);
// Replace an order
const replaceResult = await monaco.trading.replaceOrder("order-id", {
quantity: "0.002",
price: "51000"
});
console.log("Order replaced:", replaceResult.order_id);
// Cancel an order
const cancelResult = await monaco.trading.cancelOrder("order-id");
console.log("Order cancelled:", cancelResult.status);
// Get specific order
const orderDetails = await monaco.trading.getOrder("order-id");
console.log("Order details:", orderDetails.order);
}API Reference
MonacoSDK
The main SDK class that provides access to all protocol features.
class MonacoSDK {
readonly applications: ApplicationsAPI;
readonly auth: AuthAPI;
readonly vault: VaultAPI;
readonly trading: TradingAPI;
readonly market: MarketAPI;
readonly profile: ProfileAPI;
readonly websocket: {
orders: OrdersWebSocketClient;
ohlcv: OHLCVWebSocketClient;
orderbook: OrderbookWebSocketClient;
};
readonly walletClient: WalletClient;
readonly publicClient: PublicClient;
constructor(config: SDKConfig);
// Authentication
login(clientId: string, options?: { connectWebSocket?: boolean }): Promise<AuthState>;
logout(): Promise<void>;
refreshAuth(): Promise<AuthState>;
getAuthState(): AuthState | undefined;
isAuthenticated(): boolean;
// Network utilities
isConnected(): boolean;
getAccountAddress(): string;
getNetwork(): Network;
getChainId(): number;
waitForTransaction(hash: string, confirmations?: number, timeout?: number): Promise<TransactionReceipt>;
}Configuration
interface SDKConfig {
/** Wallet client for signing operations */
walletClient: WalletClient;
/** Optional network override (defaults to 'mainnet') */
network?: Network;
/** Optional transport for the public client */
transport?: Transport;
}Authentication & Token Management
The SDK uses JWT tokens for authentication. Understanding the token structure is important:
// After login, you receive an AuthState object
const authState = await sdk.login(clientId);
// AuthState structure:
interface AuthState {
accessToken: string; // For making authenticated API requests
refreshToken: string; // For refreshing tokens AND revoking (logout)
expiresAt: number; // When the access token expires
user: User; // User information
}⚠️ Important: The authentication response contains refreshToken, NOT revokeToken.
// ✅ CORRECT: Revoke using refreshToken
await sdk.auth.revokeToken(authState.refreshToken);
// 💡 TIP: Use the built-in logout method
await sdk.logout(); // Automatically calls revokeToken internallyToken Management Methods:
login(clientId, options?)- Authenticate and get tokensclientId: Your application's client IDoptions.connectWebSocket: (optional) Auto-connect all authenticated WebSocket channels after login (default:false)
logout()- Revoke token and clear staterefreshAuth()- Refresh the access token using the stored refresh tokenisAuthenticated()- Check if user is authenticatedgetAuthState()- Get current auth state with tokens
Vault API
The vault API provides secure token management operations:
interface VaultAPI extends BaseAPI {
// Vault address management
setVaultAddress(vaultAddress: Address): void;
getVaultAddress(): Address | undefined;
// Token operations
approve(token: string, amount: bigint, autoWait?: boolean): Promise<TransactionResult>;
deposit(token: string, amount: bigint, autoWait?: boolean): Promise<TransactionResult>;
withdraw(token: string, amount: bigint, autoWait?: boolean): Promise<TransactionResult>;
// Balance queries
getBalance(token: string): Promise<Balance>;
}Trading API
The trading API provides comprehensive order management:
interface TradingAPI extends BaseAPI {
// Order placement
placeLimitOrder(
market: string,
side: OrderSide,
quantity: string,
price: string,
options?: {
tradingMode?: string;
useMasterBalance?: boolean;
expirationDate?: string;
timeInForce?: string; // "GTC", "IOC", or "FOK"
}
): Promise<CreateOrderResponse>;
placeMarketOrder(
market: string,
side: OrderSide,
quantity: string,
options?: {
tradingMode?: string;
slippageTolerance?: number;
timeInForce?: string; // "GTC", "IOC", or "FOK"
}
): Promise<CreateOrderResponse>;
// Order management
cancelOrder(orderId: string): Promise<CancelOrderResponse>;
replaceOrder(
orderId: string,
newOrder: {
price?: string;
quantity: string;
useMasterBalance?: boolean;
}
): Promise<ReplaceOrderResponse>;
// Order queries
getPaginatedOrders(params?: GetPaginatedOrdersParams): Promise<GetPaginatedOrdersResponse>;
getOrder(orderId: string): Promise<GetOrderResponse>;
}Market API
The market API provides access to trading pair metadata:
interface MarketAPI extends BaseAPI {
// Market data
getTradingPairs(): Promise<TradingPair[]>;
getTradingPairBySymbol(symbol: string): Promise<TradingPair | undefined>;
}WebSocket Authentication
The SDK provides three WebSocket clients with different authentication requirements:
Public WebSockets (OHLCV and Orderbook)
No authentication required. Provide public market data. You always connect manually:
// Step 1: Establish WebSocket connection (no authentication needed)
await monaco.websocket.ohlcv.connect();
await monaco.websocket.orderbook.connect();
// Step 2: Subscribe to public market data
monaco.websocket.ohlcv.subscribeToOHLCV("BTC/USDC", "SPOT", "1m", (event) => {
console.log("OHLCV data:", event.candlestick);
});
monaco.websocket.orderbook.subscribeToOrderbookEvents("BTC/USDC", "SPOT", (event) => {
console.log("Orderbook update:", event.bids.length, "bids");
});Authenticated WebSockets (Orders)
Requires JWT authentication for personal order updates. You can either auto-connect during login or connect manually:
Option 1: Auto-connect (recommended for authenticated channels)
// Login and auto-connect all authenticated WebSocket channels
// Currently includes: Orders (personal order updates)
await monaco.login(clientId, { connectWebSocket: true });
// Subscribe to personal order events (already connected)
monaco.websocket.orders.subscribeToOrderEvents("BTC/USDC", "SPOT", (event) => {
console.log("Personal order event:", event.eventType);
});Option 2: Manual connection (required for public channels, optional for authenticated)
// Public channels like OHLCV always require manual connection (no auth needed)
await monaco.websocket.ohlcv.connect();
monaco.websocket.ohlcv.subscribeToOHLCV("BTC/USDC", "SPOT", "1m", (event) => {
console.log("OHLCV data:", event.candlestick);
});
// For authenticated channels, you can also connect manually for more control
await monaco.login(clientId);
await monaco.websocket.orders.connect();
monaco.websocket.orders.subscribeToOrderEvents("BTC/USDC", "SPOT", (event) => {
console.log("Personal order event:", event.eventType);
});Note:
- The
connectWebSocket: trueoption automatically connects all authenticated WebSocket channels (currently Orders). - Public WebSocket clients (OHLCV, Orderbook) always require calling
connect()explicitly as they don't require authentication.
Error Handling
The SDK uses structured error classes for comprehensive error handling:
import { APIError, ContractError, TransactionError, OrderError } from "@0xmonaco/core";
try {
await sdk.vault.deposit(token, amount);
} catch (error) {
if (error instanceof ContractError) {
console.error("Contract error:", error.message);
console.error("Error code:", error.code);
} else if (error instanceof APIError) {
console.error("API error:", error.message);
console.error("Status:", error.status);
} else if (error instanceof TransactionError) {
console.error("Transaction error:", error.message);
} else if (error instanceof OrderError) {
console.error("Order error:", error.message);
console.error("Market:", error.market);
}
}Error Types:
MonacoCoreError: Base error class for all SDK errorsAPIError: API request failures and communication errorsContractError: Smart contract operation errorsTransactionError: Blockchain transaction errorsOrderError: Trading order specific errorsInvalidConfigError: Configuration validation errorsInvalidStateError: Invalid state or operation errors
Development
Project Structure
packages/core/
├── src/ # Source code
│ ├── api/ # API implementations
│ │ ├── applications/ # Applications API
│ │ ├── auth/ # Authentication API
│ │ ├── base.ts # Base API class
│ │ ├── market/ # Market data API
│ │ ├── profile/ # Profile management API
│ │ ├── trading/ # Trading operations API
│ │ ├── vault/ # Vault operations API
│ │ ├── websocket/ # WebSocket client
│ │ └── index.ts # API exports
│ ├── constants/ # Constants and configurations
│ ├── errors.ts # Error classes and codes
│ ├── networks.ts # Network endpoint configurations
│ ├── sdk.ts # Main SDK implementation
│ └── index.ts # Public API exports
├── tests/ # Test suite
├── dist/ # Compiled output
├── package.json # Package configuration
└── tsconfig.json # TypeScript configurationDevelopment Setup
- Clone the repository:
git clone https://github.com/monaco-protocol/monaco-monorepo.git
cd monaco-monorepo- Install dependencies:
pnpm install- Build the package:
pnpm build --filter @0xmonaco/coreTesting
Run the test suite:
pnpm test --filter @0xmonaco/coreCode Style
The project uses ESLint and Prettier for code formatting. Run the linter:
pnpm lint --filter @0xmonaco/coreSecurity Features
JWT Authentication
- Token-based security: Secure JWT tokens for API access
- EIP-712 login: Wallet signature-based authentication
- Automatic refresh: Seamless token renewal
- Session management: Secure session handling
API Gateway Integration
- Secure communication: TLS encryption for all API calls
- Token validation: Backend validates all JWT tokens
- Rate limiting: Protection against abuse
- Audit logging: Complete transaction history
On-chain Security
- Smart contract validation: All operations validated on-chain
- Signature verification: EIP-712 signatures for authentication
- Multi-signature support: Advanced security for institutional users
Performance Considerations
- Batch operations: Efficient handling of multiple operations
- Connection pooling: Optimized API connections
- Caching: Smart caching of frequently accessed data
- Async operations: Non-blocking operations for better UX
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Workflow
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For support, please:
- Open an issue on GitHub
- Join our Discord community
- Visit our documentation site
- Check our API documentation
