@shogun-sdk/money-legos
Core SDK for cross-chain swaps, NFT purchases, token balances, and DeFi operations across multiple blockchains.
Quick Start
1. Install the Package
Choose your preferred package manager:
npm
npm install @shogun-sdk/money-legos
pnpm
pnpm add @shogun-sdk/money-legos
yarn
yarn add @shogun-sdk/money-legos
2. Initialize and Use
Set up the SDK and start making cross-chain operations:
import { init, LegoClient, OneShotClient, ShogunBalancesApiClient } from '@shogun-sdk/money-legos';
init({
rpcUrls: {
1: ['https://your-ethereum-rpc-url'],
8453: ['https://your-base-rpc-url'],
42161: ['https://your-arbitrum-rpc-url'],
7565164: ['https://your-solana-rpc-url'],
}
});
const legoClient = new LegoClient({
apiKey: 'YOUR_API_KEY'
});
const oneShotClient = new OneShotClient(
'YOUR_API_KEY',
'SHOGUN_API_URL'
);
const balancesClient = new ShogunBalancesApiClient('YOUR_API_KEY');
async function purchaseNFT() {
const result = await legoClient.MagicEden.SwapForNFT({
items: [{
address: '0x7E0b0363804C6C79AAb9aB51850bF8F3D561f868',
tokenId: '42'
}],
token: {
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
decimals: 18,
chainId: 1
},
userAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
});
if (result.status) {
console.log('Success! Transaction steps:', result.data.steps);
}
}
async function checkBalances() {
const evmBalances = await balancesClient.getEvmWalletBalance(
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
);
console.log('EVM Balances:', evmBalances);
}
3. Explore All Features
Check the sections below for comprehensive examples:
Features
- π Cross-Chain Swaps - Swap tokens between EVM chains and Solana
- πΌοΈ NFT Purchases - Buy NFTs on any chain using any supported token
- π° Balance Checking - Check token balances across multiple chains
- π Multi-Chain Support - Ethereum, Base, Arbitrum, BSC, Bera Chain, Solana, Sonic
- β‘ Transaction Signing - Built-in support for EVM and Solana transactions
- π Price Feeds - Real-time token pricing and market data
- π‘οΈ Type Safety - Full TypeScript support with comprehensive types
- π§ Flexible Configuration - Multiple RPC configuration options
Configuration Options
RPC URL Configuration
Option 1: Initialization Function (Recommended)
Best for Next.js and when you want full control over RPC URLs:
import { init } from '@shogun-sdk/money-legos';
init({
rpcUrls: {
1: ['https://your-ethereum-rpc-url'],
8453: ['https://your-base-rpc-url'],
42161: ['https://your-arbitrum-rpc-url'],
56: ['https://your-bsc-rpc-url'],
80094: ['https://your-berachain-rpc-url'],
7565164: ['https://your-solana-rpc-url'],
146: ['https://your-sonic-rpc-url'],
}
});
Option 2: Environment Variables
Node.js (.env)
RPC_URL_1=https://your-ethereum-rpc-url
RPC_URL_8453=https://your-base-rpc-url
RPC_URL_42161=https://your-arbitrum-rpc-url
RPC_URL_56=https://your-bsc-rpc-url
RPC_URL_80094=https://your-berachain-rpc-url
RPC_URL_7565164=https://your-solana-rpc-url
RPC_URL_146=https://your-sonic-rpc-url
Next.js (.env.local)
NEXT_PUBLIC_RPC_URL_1=https://your-ethereum-rpc-url
NEXT_PUBLIC_RPC_URL_8453=https://your-base-rpc-url
NEXT_PUBLIC_RPC_URL_42161=https://your-arbitrum-rpc-url
NEXT_PUBLIC_RPC_URL_56=https://your-bsc-rpc-url
NEXT_PUBLIC_RPC_URL_80094=https://your-berachain-rpc-url
NEXT_PUBLIC_RPC_URL_7565164=https://your-solana-rpc-url
NEXT_PUBLIC_RPC_URL_146=https://your-sonic-rpc-url
Vite (.env)
VITE_RPC_URL_1=https://your-ethereum-rpc-url
VITE_RPC_URL_8453=https://your-base-rpc-url
VITE_RPC_URL_42161=https://your-arbitrum-rpc-url
Option 3: Vite Plugin Configuration
For Vite applications, use the env-compatible plugin:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import envCompatible from 'vite-plugin-env-compatible';
export default defineConfig({
plugins: [
react(),
envCompatible({
prefix: 'RPC_URL_',
}),
],
});
Supported Chains
import {
ETHEREUM_CHAIN_ID,
BASE_CHAIN_ID,
ARBITRUM_CHAIN_ID,
BSC_CHAIN_ID,
BERA_CHAIN_ID,
SOLANA_CHAIN_ID,
SONIC_CHAIN_ID,
getSupportedChains,
CHAIN_MAP
} from '@shogun-sdk/money-legos';
const supportedChains = getSupportedChains();
console.log('Supported chains:', supportedChains);
Usage Examples
NFT Purchase Examples
Basic NFT Purchase
import { LegoClient } from '@shogun-sdk/money-legos';
const legoClient = new LegoClient({ apiKey: 'YOUR_API_KEY' });
async function purchaseNFTWithETH() {
const result = await legoClient.MagicEden.SwapForNFT({
items: [{
address: '0x7E0b0363804C6C79AAb9aB51850bF8F3D561f868',
tokenId: '42'
}],
token: {
address: '0x0000000000000000000000000000000000000000',
decimals: 18,
chainId: 1
},
userAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
});
if (result.status) {
console.log('Success! Transaction steps:', result.data.steps);
} else {
console.error('Failed:', result.error);
}
}
Multiple NFTs Purchase
async function purchaseMultipleNFTs() {
const result = await legoClient.MagicEden.SwapForNFT({
items: [
{ address: '0x7E0b0363804C6C79AAb9aB51850bF8F3D561f868', tokenId: '42' },
{ address: '0x7E0b0363804C6C79AAb9aB51850bF8F3D561f868', tokenId: '43' },
{ address: '0x7E0b0363804C6C79AAb9aB51850bF8F3D561f868', tokenId: '44' }
],
token: {
address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
decimals: 8,
chainId: 1
},
userAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
});
console.log('Multiple NFT purchase result:', result);
}
Different Token Purchases
async function purchaseWithUSDC() {
const result = await legoClient.MagicEden.SwapForNFT({
items: [{ address: '0x...', tokenId: '1' }],
token: {
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
decimals: 6,
chainId: 1
},
userAddress: '0x...'
});
}
async function purchaseWithDAI() {
const result = await legoClient.MagicEden.SwapForNFT({
items: [{ address: '0x...', tokenId: '1' }],
token: {
address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
decimals: 18,
chainId: 1
},
userAddress: '0x...'
});
}
Balance Checking Examples
import { ShogunBalancesApiClient } from '@shogun-sdk/money-legos';
const balancesClient = new ShogunBalancesApiClient('YOUR_API_KEY');
async function checkEVMBalances() {
const balances = await balancesClient.getEvmWalletBalance(
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
);
console.log('EVM Balances:', balances);
balances.forEach(balance => {
console.log(`${balance.symbol}: ${balance.balance} (${balance.usdValue} USD)`);
});
}
async function checkSolanaBalances() {
const balances = await balancesClient.getSolanaTokenBalances(
'YourSolanaWalletAddress'
);
console.log('Solana Balances:', balances);
}
async function getTokenPrice() {
const tokenPrice = await balancesClient.getTokenUSDPrice(
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
1
);
console.log('WETH Price:', tokenPrice);
}
async function getTokenInfo() {
const tokenInfo = await balancesClient.getTokenInfo(
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
1
);
console.log('Token Info:', {
name: tokenInfo.name,
symbol: tokenInfo.symbol,
decimals: tokenInfo.decimals,
totalSupply: tokenInfo.totalSupply
});
}
Cross-Chain Swap Examples
import { OneShotClient } from '@shogun-sdk/money-legos';
const oneShotClient = new OneShotClient('YOUR_API_KEY', 'SHOGUN_API_URL');
async function swapETHToUSDCOnBase() {
const quote = await oneShotClient.fetchQuote({
srcChain: 1,
destChain: 8453,
srcToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
destToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
amount: '1000000000000000000',
senderAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
slippage: 0.5,
});
if (quote.status) {
console.log('Cross-chain swap quote:', quote.data);
} else {
console.error('Failed to get quote:', quote.error);
}
}
async function swapSOLToETH() {
const quote = await oneShotClient.fetchQuote({
srcChain: 7565164,
destChain: 1,
srcToken: 'So11111111111111111111111111111111111111112',
destToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
amount: '1000000000',
senderAddress: 'YourSolanaAddress',
slippage: 0.5,
});
console.log('SOL to ETH quote:', quote);
}
Transaction Signing
EVM Transaction Execution with Viem
import { createWalletClient, http, getPublicClient } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';
import { LegoClient } from '@shogun-sdk/money-legos';
async function executeEVMTransactionWithViem() {
const account = privateKeyToAccount('0x...');
const client = createWalletClient({
chain: base,
transport: http(),
account,
});
const legoClient = new LegoClient({ apiKey: 'YOUR_API_KEY' });
try {
const { data } = await legoClient.MagicEden.SwapForNFT({
token: {
address: '0x0000000000000000000000000000000000000000',
decimals: 18,
chainId: 8453,
},
items: [{
address: '0x72d876d9cdf4001b836f8e47254d0551eda2eebb',
tokenId: '32',
}],
userAddress: account.address,
});
if (!data) {
console.error('No transaction data returned');
return;
}
for (const step of data.steps) {
console.log(`Executing: ${step.description || 'Transaction step'}`);
const txHash = await client.sendTransaction({
to: step.to as `0x${string}`,
data: step.data as `0x${string}`,
value: BigInt(step.value),
chainId: step.chainId,
gas: BigInt(step.gas),
maxFeePerGas: BigInt(step.maxFeePerGas),
maxPriorityFeePerGas: BigInt(step.maxPriorityFeePerGas),
});
console.log(`Transaction successful! Hash: ${txHash}`);
}
} catch (error) {
console.error('Transaction execution failed:', error);
}
}
Advanced EVM Transaction Handling
import { QuoteTypes } from '@shogun-sdk/money-legos';
async function handleAdvancedEVMTransaction(
quote: QuoteTypes,
signer: any,
chain: any
): Promise<{ hash: string; swapPlacementTimestamp: number; swapExecutionTimestamp: number } | null> {
try {
if (Array.isArray(quote.calldatas) || !signer) return null;
const provider = getPublicClient({ chain });
const estimatedGas = await provider.estimateGas({
to: quote.calldatas.to as `0x${string}`,
data: quote.calldatas.data as `0x${string}`,
value: BigInt(quote.calldatas?.value ?? 0),
account: signer.account,
});
const gas = BigInt(Math.ceil(Number(estimatedGas) * 1.2));
const swapPlacementTimestamp = Date.now();
const hash = await signer.sendTransaction({
to: quote.calldatas.to as `0x${string}`,
data: quote.calldatas.data as `0x${string}`,
value: BigInt(quote.calldatas?.value ?? 0),
account: signer.account,
gas,
chain,
});
const tx = await provider.waitForTransactionReceipt({
hash,
retryCount: 5,
confirmations: 1,
});
const swapExecutionTimestamp = Date.now();
if (tx.status !== 'success') {
throw new Error(`Transaction failed: ${tx.status}`);
}
return { hash, swapPlacementTimestamp, swapExecutionTimestamp };
} catch (error) {
console.error('EVM transaction error:', error);
throw error;
}
}
Solana Transaction Execution
import { VersionedTransaction } from '@solana/web3.js';
import bs58 from 'bs58';
import {
sendTransactionUsingJito,
sendBundleUsingJito,
isValidSolanaSignature,
checkTransactionConfirmation,
confirmTransaction,
} from '@shogun-sdk/money-legos';
async function handleSolanaTransaction(
quote: QuoteTypes,
address: string,
walletSigner: any
): Promise<{ transactionHash: string; swapPlacementTimestamp: number; swapExecutionTimestamp: number } | null> {
if (!Array.isArray(quote.calldatas)) return null;
try {
const transactions = await Promise.all(
quote.calldatas.map(async (calldata) => {
const messageBuffer = Buffer.from(calldata.data, 'base64');
return VersionedTransaction.deserialize(messageBuffer);
}),
);
const signedTransactions = await walletSigner.signAllTransactions!(
transactions,
address,
);
if (!signedTransactions) {
throw new Error('Failed to sign transactions');
}
const base58Transactions = signedTransactions.map((tx) =>
bs58.encode(tx.serialize())
);
const swapPlacementTimestamp = Date.now();
let result;
if (quote.calldatas.length === 1) {
result = await handleSingleSolanaTransaction(base58Transactions[0]);
} else {
result = await handleSolanaBundleTransaction(
base58Transactions,
transactions[0]
);
}
const swapExecutionTimestamp = Date.now();
return {
transactionHash: result.transactionHash,
swapPlacementTimestamp,
swapExecutionTimestamp,
};
} catch (error) {
console.error('Solana transaction error:', error);
throw error;
}
}
async function handleSingleSolanaTransaction(
base58Transaction: string
): Promise<{ transactionHash: string }> {
const transactionHash = await sendTransactionUsingJito(base58Transaction);
const confirmation = await confirmTransaction(transactionHash, {
maxRetries: 50,
commitment: 'confirmed',
checkInterval: 200,
});
if (!confirmation.success) {
throw new Error(`Transaction failed: ${confirmation.error}`);
}
return { transactionHash };
}
async function handleSolanaBundleTransaction(
base58Transactions: string[],
firstTransaction: VersionedTransaction,
): Promise<{ transactionHash: string }> {
const transactionSignature = firstTransaction?.signatures?.[0];
if (!transactionSignature) {
throw new Error('Missing transaction signature');
}
const transactionHash = bs58.encode(transactionSignature);
if (!isValidSolanaSignature(transactionHash)) {
throw new Error('Invalid transaction signature format');
}
const bundleID = await sendBundleUsingJito(base58Transactions);
const confirmed = await checkTransactionConfirmation(
provider,
firstTransaction,
transactionHash
);
if (!confirmed) {
throw new Error('Bundle transaction failed to confirm');
}
return { transactionHash };
}
Error Handling
Comprehensive Error Handling
async function robustNFTPurchase() {
try {
const result = await legoClient.MagicEden.SwapForNFT({
items: [{ address: '0x123...', tokenId: '1' }],
token: { address: '0xabc...', decimals: 18, chainId: 1 },
userAddress: '0xdef...'
});
if (!result.status) {
switch (result.error) {
case 'INSUFFICIENT_BALANCE':
console.error('β Not enough tokens to complete purchase');
break;
case 'INVALID_NFT':
console.error('β NFT not found or unavailable');
break;
case 'PRICE_CHANGED':
console.error('β Price changed during transaction');
break;
case 'NETWORK_ERROR':
console.error('β Network connection issues');
break;
case 'API_RATE_LIMIT':
console.error('β Too many requests, please wait');
break;
default:
console.error(`β Purchase failed: ${result.error}`);
}
return { success: false, error: result.error };
}
console.log('β
Purchase data ready:', result.data);
return { success: true, data: result.data };
} catch (error) {
if (error instanceof Error) {
console.error('π₯ Unexpected error:', {
message: error.message,
stack: error.stack,
name: error.name
});
if (error.message.includes('fetch')) {
console.error('Network issue detected');
}
if (error.message.includes('JSON')) {
console.error('API response format issue');
}
} else {
console.error('π₯ Unknown error type:', error);
}
return { success: false, error: 'Unexpected error occurred' };
}
}
async function purchaseWithRetry(maxRetries = 3) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`π Attempt ${attempt}/${maxRetries}`);
const result = await robustNFTPurchase();
if (result.success) {
return result;
}
lastError = result.error;
if (['INSUFFICIENT_BALANCE', 'INVALID_NFT'].includes(result.error)) {
break;
}
} catch (error) {
lastError = error;
console.error(`β Attempt ${attempt} failed:`, error);
}
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`β³ Waiting ${delay}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error(`All ${maxRetries} attempts failed. Last error: ${lastError}`);
}
API Reference
LegoClient
Constructor
new LegoClient(config: LegoClientConfig)
Parameters:
config.apiKey (string): Your API key from Shogun dashboard
config.baseUrl (string, optional): Custom API base URL
Methods
MagicEden.SwapForNFT(props: FetchLegoProps): Promise<LegoResult>
Purchase NFTs using any supported token.
Parameters:
props.items (NFTItem[]): Array of NFT items to purchase
props.token (Token): Token to use for payment
props.userAddress (string): Buyer's wallet address
Returns:
interface LegoResult {
status: boolean;
error?: string;
data?: {
steps: TransactionStep[];
details: PurchaseDetails;
fees: FeeInformation;
};
isLoading: boolean;
refetch: () => Promise<LegoResult>;
}
OneShotClient
Constructor
new OneShotClient(apiKey: string, baseUrl: string)
Methods
fetchQuote(params: QuoteParams): Promise<QuoteResponse>
Get a quote for cross-chain token swaps.
Parameters:
interface QuoteParams {
srcChain: number;
destChain: number;
srcToken: string;
destToken: string;
amount: string;
senderAddress: string;
slippage: number;
}
Returns:
interface QuoteResponse {
status: boolean;
error?: string;
data?: QuoteTypes;
}
ShogunBalancesApiClient
Constructor
new ShogunBalancesApiClient(apiKey: string)
Methods
getEvmWalletBalance(address: string): Promise<EvmBalance[]>
Get token balances for an EVM wallet.
Returns:
interface EvmBalance {
tokenAddress: string;
symbol: string;
name: string;
decimals: number;
balance: string;
usdValue: number;
chainId: number;
}
getSolanaTokenBalances(address: string): Promise<SolanaBalance[]>
Get token balances for a Solana wallet.
getTokenUSDPrice(tokenAddress: string, chainId: number): Promise<TokenPrice>
Get current USD price for a token.
getTokenInfo(tokenAddress: string, chainId: number): Promise<TokenInfo>
Get comprehensive token information.
Core Types
interface NFTItem {
address: string;
tokenId: string;
}
interface Token {
address: string;
decimals: number;
chainId: number;
}
interface TransactionStep {
to: string;
data: string;
value: string;
chainId: number;
gas: string;
maxFeePerGas: string;
maxPriorityFeePerGas: string;
description?: string;
}
Best Practices
1. Always Validate Response Status
const result = await legoClient.MagicEden.SwapForNFT({...});
if (!result.status) {
console.error('Operation failed:', result.error);
return;
}
2. Use TypeScript for Type Safety
import { LegoClient, NFTItem, Token, TransactionStep } from '@shogun-sdk/money-legos';
const items: NFTItem[] = [
{ address: '0x...', tokenId: '42' }
];
const token: Token = {
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
decimals: 18,
chainId: 1
};
3. Secure API Key Management
const client = new LegoClient({ apiKey: 'sk_live_abc123...' });
const client = new LegoClient({
apiKey: process.env.SHOGUN_API_KEY!
});
if (!process.env.SHOGUN_API_KEY) {
throw new Error('SHOGUN_API_KEY environment variable is required');
}
4. Implement Proper Error Boundaries
class ShogunSDKError extends Error {
constructor(
message: string,
public code: string,
public originalError?: any
) {
super(message);
this.name = 'ShogunSDKError';
}
}
async function safeExecute<T>(operation: () => Promise<T>): Promise<T> {
try {
return await operation();
} catch (error) {
if (error instanceof ShogunSDKError) {
throw error;
}
throw new ShogunSDKError(
'Unexpected error in Shogun SDK operation',
'UNKNOWN_ERROR',
error
);
}
}
5. Gas Optimization
const estimatedGas = await provider.estimateGas({...});
const gasWithBuffer = BigInt(Math.ceil(Number(estimatedGas) * 1.2));
const gasPrice = await provider.getGasPrice();
console.log(`Current gas price: ${gasPrice} gwei`);
Common Use Cases
1. Cross-Chain NFT Marketplace
class CrossChainNFTMarketplace {
constructor(private apiKey: string) {}
async purchaseNFTFromAnyChain(
nftContract: string,
tokenId: string,
paymentToken: Token,
buyerAddress: string
) {
const legoClient = new LegoClient({ apiKey: this.apiKey });
const result = await legoClient.MagicEden.SwapForNFT({
items: [{ address: nftContract, tokenId }],
token: paymentToken,
userAddress: buyerAddress
});
if (!result.status) {
throw new Error(`Purchase failed: ${result.error}`);
}
return result.data;
}
}
2. Portfolio Tracker
class PortfolioTracker {
constructor(private apiKey: string) {
this.balancesClient = new ShogunBalancesApiClient(apiKey);
}
async getFullPortfolio(evmAddress: string, solanaAddress: string) {
const [evmBalances, solanaBalances] = await Promise.all([
this.balancesClient.getEvmWalletBalance(evmAddress),
this.balancesClient.getSolanaTokenBalances(solanaAddress)
]);
const totalUSDValue = [
...evmBalances,
...solanaBalances
].reduce((sum, balance) => sum + balance.usdValue, 0);
return {
evmBalances,
solanaBalances,
totalUSDValue,
lastUpdated: new Date().toISOString()
};
}
}
3. Cross-Chain DeFi Aggregator
class DeFiAggregator {
constructor(private apiKey: string, private baseUrl: string) {
this.oneShotClient = new OneShotClient(apiKey, baseUrl);
}
async findBestSwapRoute(
fromToken: Token,
toToken: Token,
amount: string,
userAddress: string
) {
const routes = [
{ srcChain: fromToken.chainId, destChain: toToken.chainId },
{ srcChain: fromToken.chainId, destChain: 1 },
{ srcChain: fromToken.chainId, destChain: 8453 },
];
const quotes = await Promise.allSettled(
routes.map(route =>
this.oneShotClient.fetchQuote({
srcChain: route.srcChain,
destChain: route.destChain,
srcToken: fromToken.address,
destToken: toToken.address,
amount,
senderAddress: userAddress,
slippage: 0.5
})
)
);
const validQuotes = quotes
.filter((result): result is PromiseFulfilledResult<any> =>
result.status === 'fulfilled' && result.value.status
)
.map(result => result.value.data);
return validQuotes.sort((a, b) =>
parseFloat(b.outputAmount) - parseFloat(a.outputAmount)
)[0];
}
}
Hyperliquid Integration
The Hyperliquid integration provides comprehensive trading capabilities for perpetual futures and spot trading on the Hyperliquid exchange.
Quick Start
import { Hyperliquid } from '@shogun-sdk/money-legos';
const hyperliquid = new Hyperliquid({
privateKey: 'YOUR_PRIVATE_KEY',
testnet: false,
walletAddress: '0x...',
vaultAddress: '0x...',
});
await hyperliquid.connect();
Configuration Options
interface HyperliquidConfig {
privateKey?: string;
testnet?: boolean;
walletAddress?: string;
vaultAddress?: string;
maxReconnectAttempts?: number;
}
Trading Operations
Place Orders
const marketOrder = await hyperliquid.custom.marketOpen(
'BTC',
true,
0.1,
undefined,
0.05,
'cloid-123'
);
const limitOrder = await hyperliquid.exchange.placeOrder({
coin: 'BTC',
is_buy: true,
sz: 0.1,
limit_px: 45000,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false,
cloid: 'my-order-123'
});
const stopLossOrder = await hyperliquid.exchange.placeOrder({
coin: 'BTC',
is_buy: false,
sz: 0.1,
limit_px: 43000,
order_type: {
trigger: {
triggerPx: 44000,
isMarket: true,
tpsl: 'sl'
}
},
reduce_only: true
});
const takeProfitOrder = await hyperliquid.exchange.placeOrder({
coin: 'BTC',
is_buy: false,
sz: 0.1,
limit_px: 47000,
order_type: {
trigger: {
triggerPx: 46000,
isMarket: false,
tpsl: 'tp'
}
},
reduce_only: true
});
Order Types and Time-in-Force
type OrderType = {
limit?: { tif: 'Alo' | 'Ioc' | 'Gtc' };
trigger?: {
triggerPx: string | number;
isMarket: boolean;
tpsl: 'tp' | 'sl';
};
};
const multipleOrders = await hyperliquid.exchange.placeOrder({
orders: [
{
coin: 'BTC',
is_buy: true,
sz: 0.1,
limit_px: 45000,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
},
{
coin: 'ETH',
is_buy: true,
sz: 1.0,
limit_px: 3000,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
}
],
grouping: 'na'
});
Cancel Orders
const cancelResponse = await hyperliquid.exchange.cancelOrder({
coin: 'BTC',
o: 123456789
});
const cancelByCloid = await hyperliquid.exchange.cancelOrderByCloid(
'BTC',
'my-order-123'
);
const cancelMultiple = await hyperliquid.exchange.cancelOrder([
{ coin: 'BTC', o: 123456789 },
{ coin: 'ETH', o: 987654321 }
]);
const cancelAllBTC = await hyperliquid.custom.cancelAllOrders('BTC');
const cancelAll = await hyperliquid.custom.cancelAllOrders();
Modify Orders
const modifyResponse = await hyperliquid.exchange.modifyOrder(
123456789,
{
coin: 'BTC',
is_buy: true,
sz: 0.2,
limit_px: 45500,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
}
);
const batchModify = await hyperliquid.exchange.batchModifyOrders([
{
oid: 123456789,
order: {
coin: 'BTC',
is_buy: true,
sz: 0.2,
limit_px: 45500,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
}
},
{
oid: 987654321,
order: {
coin: 'ETH',
is_buy: true,
sz: 2.0,
limit_px: 3100,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
}
}
]);
Position Management
Close Positions
const closePosition = await hyperliquid.custom.marketClose(
'BTC',
0.1,
undefined,
0.05,
'close-123'
);
const closeAllPositions = await hyperliquid.custom.closeAllPositions(0.05);
Update Leverage
const updateLeverage = await hyperliquid.exchange.updateLeverage(
'BTC',
'cross',
10
);
const updateMargin = await hyperliquid.exchange.updateIsolatedMargin(
'BTC',
true,
1000
);
Market Data and Information
Get Market Data
const allMids = await hyperliquid.info.getAllMids();
console.log('BTC Price:', allMids['BTC']);
const orderBook = await hyperliquid.info.getL2Book('BTC');
console.log('Bids:', orderBook.levels[0]);
console.log('Asks:', orderBook.levels[1]);
const candles = await hyperliquid.info.getCandleSnapshot(
'BTC',
'1h',
Date.now() - 86400000,
Date.now()
);
const perpMeta = await hyperliquid.info.perpetuals.getPerpMeta();
console.log('Available perpetuals:', perpMeta.universe);
const spotMeta = await hyperliquid.info.spot.getSpotMeta();
console.log('Available spot pairs:', spotMeta.universe);
Get User Data
const userAddress = '0x...';
const positions = await hyperliquid.info.perpetuals.getClearinghouseState(userAddress);
console.log('Positions:', positions.assetPositions);
const openOrders = await hyperliquid.info.getUserOpenOrders(userAddress);
console.log('Open orders:', openOrders);
const fills = await hyperliquid.info.getUserFills(userAddress);
console.log('Recent fills:', fills);
const fillsByTime = await hyperliquid.info.getUserFillsByTime(
userAddress,
Date.now() - 86400000,
Date.now()
);
const portfolio = await hyperliquid.info.getUserPortfolio(userAddress);
console.log('Portfolio data:', portfolio);
const spotBalances = await hyperliquid.info.spot.getSpotClearinghouseState(userAddress);
console.log('Spot balances:', spotBalances.balances);
TWAP Orders
const twapOrder = await hyperliquid.exchange.placeTwapOrder({
coin: 'BTC',
is_buy: true,
sz: 1.0,
reduce_only: false,
minutes: 30,
randomize: true
});
console.log('TWAP ID:', twapOrder.response.data.status.running.twapId);
const cancelTwap = await hyperliquid.exchange.cancelTwapOrder({
coin: 'BTC',
twap_id: twapOrder.response.data.status.running.twapId
});
const twapFills = await hyperliquid.info.getUserTwapSliceFills(userAddress);
console.log('TWAP fills:', twapFills);
Transfers and Withdrawals
USDC Transfers
const usdcTransfer = await hyperliquid.exchange.usdTransfer(
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
100
);
const withdrawal = await hyperliquid.exchange.initiateWithdrawal(
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
100
);
Spot Token Transfers
const spotTransfer = await hyperliquid.exchange.spotTransfer(
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
'PURR',
'1000'
);
const spotPerpTransfer = await hyperliquid.exchange.transferBetweenSpotAndPerp(
100,
true
);
Vault Operations
const vaultHyperliquid = new Hyperliquid({
privateKey: 'YOUR_PRIVATE_KEY',
vaultAddress: '0x...'
});
const vaultDeposit = await hyperliquid.exchange.vaultTransfer(
'0x...',
true,
1000
);
const vaultWithdraw = await hyperliquid.exchange.vaultTransfer(
'0x...',
false,
500
);
const vaultDetails = await hyperliquid.info.getVaultDetails(
'0x...',
userAddress
);
const vaultEquities = await hyperliquid.info.getUserVaultEquities(userAddress);
Advanced Features
Spot Trading
const spotAssets = await hyperliquid.custom.getAllAssets();
console.log('Spot assets:', spotAssets.spot);
const spotBuy = await hyperliquid.exchange.placeOrder({
coin: 'PURR/USDC',
is_buy: true,
sz: 1000,
limit_px: 0.001,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
});
Batch Operations
const scheduleCancel = await hyperliquid.exchange.scheduleCancel(
Date.now() + 3600000
);
const setReferrer = await hyperliquid.exchange.setReferrer('YOUR_REFERRER_CODE');
const approveAgent = await hyperliquid.exchange.approveAgent({
agentAddress: '0x...',
agentName: 'Trading Bot'
});
Rate Limiting and Status
const rateLimit = await hyperliquid.info.getUserRateLimit(userAddress);
console.log('Rate limit status:', rateLimit);
const orderStatus = await hyperliquid.info.getOrderStatus(
userAddress,
123456789
);
console.log('Order status:', orderStatus);
const isAuthenticated = hyperliquid.isAuthenticated();
console.log('Authenticated:', isAuthenticated);
Error Handling
async function safeTrading() {
try {
const order = await hyperliquid.exchange.placeOrder({
coin: 'BTC',
is_buy: true,
sz: 0.1,
limit_px: 45000,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false
});
if (order.status === 'ok') {
console.log('Order placed successfully:', order.response);
} else {
console.error('Order failed:', order.response);
}
} catch (error) {
if (error.message.includes('Invalid or missing private key')) {
console.error('Authentication required for trading operations');
} else if (error.message.includes('Unknown asset')) {
console.error('Invalid symbol provided');
} else if (error.message.includes('Invalid price')) {
console.error('Price does not meet tick size requirements');
} else {
console.error('Trading error:', error);
}
}
}
Best Practices
1. Price Precision
const isValidPrice = await hyperliquid.custom.isValidPrice('BTC', 45000.5);
if (!isValidPrice) {
const adjustedPrice = await hyperliquid.custom.adjustPrice('BTC', 45000.5);
}
2. Order Management
const cloid = `order-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const order = await hyperliquid.exchange.placeOrder({
coin: 'BTC',
is_buy: true,
sz: 0.1,
limit_px: 45000,
order_type: { limit: { tif: 'Gtc' } },
reduce_only: false,
cloid: cloid
});
orderTracker.set(cloid, order);
3. Position Sizing
const positions = await hyperliquid.info.perpetuals.getClearinghouseState(userAddress);
const accountValue = parseFloat(positions.marginSummary.accountValue);
const availableBalance = parseFloat(positions.withdrawable);
const riskPercentage = 0.02;
const stopLossDistance = 1000;
const maxPositionSize = (accountValue * riskPercentage) / stopLossDistance;
4. Symbol Conversion
const internalSymbol = await hyperliquid.info.getInternalName('BTC-PERP');
const displaySymbol = await hyperliquid.symbolConversion.convertSymbol(internalSymbol, 'forward');
Types and Interfaces
interface HyperliquidOrder {
coin: string;
is_buy: boolean;
sz: number;
limit_px: number;
order_type: OrderType;
reduce_only: boolean;
cloid?: string;
}
interface OrderResponse {
status: string;
response: {
type: string;
data: {
statuses: Array<{
resting?: { oid: number };
filled?: { oid: number; totalSz: string; avgPx: string };
}>;
};
};
}
interface Position {
coin: string;
entryPx: string;
leverage: { type: string; value: number };
liquidationPx: string;
marginUsed: string;
positionValue: string;
szi: string;
unrealizedPnl: string;
}
Troubleshooting
Common Issues and Solutions
1. API Key Issues
const isValidAPIKey = (key: string) => {
return key.startsWith('sk_') && key.length > 20;
};
if (!isValidAPIKey(process.env.SHOGUN_API_KEY!)) {
throw new Error('Invalid API key format');
}
2. RPC Configuration Issues
async function testRPCConnection(chainId: number) {
try {
const provider = getPublicClient({
chain: { id: chainId } as any,
transport: http()
});
const blockNumber = await provider.getBlockNumber();
console.log(`β
Chain ${chainId} connected, latest block: ${blockNumber}`);
return true;
} catch (error) {
console.error(`β Chain ${chainId} connection failed:`, error);
return false;
}
}
3. Transaction Failures
async function debugTransaction(txHash: string, chainId: number) {
const provider = getPublicClient({ chain: { id: chainId } as any });
try {
const receipt = await provider.getTransactionReceipt({ hash: txHash as `0x${string}` });
if (receipt.status === 'reverted') {
console.error('Transaction reverted');
const tx = await provider.getTransaction({ hash: txHash as `0x${string}` });
console.log('Transaction data:', tx);
}
} catch (error) {
console.error('Failed to get transaction receipt:', error);
}
}
4. Balance Issues
async function validateBalance(
userAddress: string,
tokenAddress: string,
requiredAmount: string,
chainId: number
) {
const balancesClient = new ShogunBalancesApiClient(process.env.SHOGUN_API_KEY!);
if (chainId === 7565164) {
const balances = await balancesClient.getSolanaTokenBalances(userAddress);
const tokenBalance = balances.find(b => b.tokenAddress === tokenAddress);
return tokenBalance && parseFloat(tokenBalance.balance) >= parseFloat(requiredAmount);
} else {
const balances = await balancesClient.getEvmWalletBalance(userAddress);
const tokenBalance = balances.find(b => b.tokenAddress === tokenAddress);
return tokenBalance && parseFloat(tokenBalance.balance) >= parseFloat(requiredAmount);
}
}
Support
License
ISC