SDK Examples
Complete code examples for common Seesaw operations.
Setup
import {
Connection,
PublicKey,
Keypair,
Transaction,
sendAndConfirmTransaction,
SystemProgram,
} from '@solana/web3.js';
import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from '@solana/spl-token';
import {
findConfigPda,
findMarketPda,
findOrderbookPda,
findVaultPda,
findPositionPda,
parseMarket,
parseOrderbook,
parsePosition,
parseConfig,
createPlaceOrderInstruction,
createCancelOrderInstruction,
createSettlePositionInstruction,
OrderSide,
OrderType,
} from '@seesaw/sdk';
// Configuration
const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
const programId = new PublicKey('SEESAW_PROGRAM_ID');
const wallet = Keypair.fromSecretKey(/* your secret key */);
Example 1: View Current Market
async function viewCurrentMarket() {
// Calculate current market ID
const now = Math.floor(Date.now() / 1000);
const durationSeconds = 900; // default; use market's actual duration
const marketId = BigInt(Math.floor(now / durationSeconds));
// Derive PDAs
const [marketPda] = findMarketPda(marketId, programId);
const [orderbookPda] = findOrderbookPda(marketPda, programId);
// Fetch accounts
const [marketAccount, orderbookAccount] = await connection.getMultipleAccountsInfo([
marketPda,
orderbookPda,
]);
if (!marketAccount) {
console.log('No market exists for current epoch');
console.log('Market ID:', marketId.toString());
console.log('Start time:', new Date(Number(marketId) * 900 * 1000));
return;
}
const market = parseMarket(marketAccount.data);
const orderbook = orderbookAccount ? parseOrderbook(orderbookAccount.data) : null;
console.log('=== Market Info ===');
console.log('Market ID:', market.marketId.toString());
console.log('Start:', new Date(Number(market.tStart) * 1000));
console.log('End:', new Date(Number(market.tEnd) * 1000));
console.log('Pyth Feed:', market.pythFeed.toBase58());
console.log('Start Price:', market.startPrice.toString());
console.log('End Price:', market.endPrice.toString());
console.log('Outcome:', market.outcome === 0 ? 'Pending' : market.outcome === 1 ? 'UP' : 'DOWN');
console.log('Total YES:', market.totalYesShares.toString());
console.log('Total NO:', market.totalNoShares.toString());
console.log('Volume:', market.totalVolume.toString());
if (orderbook) {
console.log('\n=== Order Book ===');
console.log('Best Bid:', orderbook.bestBidPrice, 'bps');
console.log('Best Ask:', orderbook.bestAskPrice, 'bps');
console.log('Spread:', orderbook.bestAskPrice - orderbook.bestBidPrice, 'bps');
console.log('Bid Count:', orderbook.bidCount);
console.log('Ask Count:', orderbook.askCount);
}
}
await viewCurrentMarket();
Example 2: Buy YES Shares
async function buyYesShares(marketId: bigint, priceBps: number, quantity: bigint) {
console.log(`Buying ${quantity} YES shares at ${priceBps} bps...`);
// 1. Derive PDAs
const [configPda] = findConfigPda(programId);
const [marketPda] = findMarketPda(marketId, programId);
const [orderbookPda] = findOrderbookPda(marketPda, programId);
const [vaultPda] = findVaultPda(marketPda, programId);
const [positionPda] = findPositionPda(marketPda, wallet.publicKey, programId);
// 2. Get market info
const marketAccount = await connection.getAccountInfo(marketPda);
if (!marketAccount) throw new Error('Market not found');
const market = parseMarket(marketAccount.data);
// 3. Get config for treasury
const configAccount = await connection.getAccountInfo(configPda);
const config = parseConfig(configAccount!.data);
// 4. Get token accounts
const userTokenAccount = await getAssociatedTokenAddress(market.settlementMint, wallet.publicKey);
const treasuryTokenAccount = await getAssociatedTokenAddress(
market.settlementMint,
config.treasury
);
// 5. Calculate required collateral
const collateralNeeded = (BigInt(priceBps) * quantity) / 10000n;
console.log(`Collateral needed: ${collateralNeeded} tokens`);
// 6. Build instruction
const placeOrderIx = createPlaceOrderInstruction(
{
market: marketPda,
orderbook: orderbookPda,
position: positionPda,
userTokenAccount,
vault: vaultPda,
user: wallet.publicKey,
config: configPda,
treasuryTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
},
{
side: OrderSide.BuyYes,
priceBps,
quantity,
orderType: OrderType.Limit,
},
programId
);
// 7. Send transaction
const tx = new Transaction().add(placeOrderIx);
const signature = await sendAndConfirmTransaction(connection, tx, [wallet]);
console.log('Order placed! Signature:', signature);
return signature;
}
// Usage: Buy 100 YES shares at 60%
const marketId = BigInt(Math.floor(Date.now() / 1000 / 900)); // 900 = default 15-min duration
await buyYesShares(marketId, 6000, BigInt(100));
Example 3: Sell NO Shares
async function sellNoShares(marketId: bigint, priceBps: number, quantity: bigint) {
console.log(`Selling ${quantity} NO shares at ${priceBps} bps...`);
// 1. Derive PDAs
const [configPda] = findConfigPda(programId);
const [marketPda] = findMarketPda(marketId, programId);
const [orderbookPda] = findOrderbookPda(marketPda, programId);
const [vaultPda] = findVaultPda(marketPda, programId);
const [positionPda] = findPositionPda(marketPda, wallet.publicKey, programId);
// 2. Check position
const positionAccount = await connection.getAccountInfo(positionPda);
if (!positionAccount) throw new Error('No position found');
const position = parsePosition(positionAccount.data);
const availableNo = position.noShares - position.lockedNoShares;
if (availableNo < quantity) {
throw new Error(`Insufficient NO shares. Available: ${availableNo}`);
}
// 3. Get market and config
const marketAccount = await connection.getAccountInfo(marketPda);
const market = parseMarket(marketAccount!.data);
const configAccount = await connection.getAccountInfo(configPda);
const config = parseConfig(configAccount!.data);
// 4. Get token accounts
const userTokenAccount = await getAssociatedTokenAddress(market.settlementMint, wallet.publicKey);
const treasuryTokenAccount = await getAssociatedTokenAddress(
market.settlementMint,
config.treasury
);
// 5. Build instruction
const placeOrderIx = createPlaceOrderInstruction(
{
market: marketPda,
orderbook: orderbookPda,
position: positionPda,
userTokenAccount,
vault: vaultPda,
user: wallet.publicKey,
config: configPda,
treasuryTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
},
{
side: OrderSide.SellNo,
priceBps,
quantity,
orderType: OrderType.Limit,
},
programId
);
// 6. Send transaction
const tx = new Transaction().add(placeOrderIx);
const signature = await sendAndConfirmTransaction(connection, tx, [wallet]);
console.log('Order placed! Signature:', signature);
return signature;
}
Example 4: View and Cancel Orders
async function viewAndCancelOrders(marketId: bigint) {
// 1. Derive PDAs
const [marketPda] = findMarketPda(marketId, programId);
const [orderbookPda] = findOrderbookPda(marketPda, programId);
const [vaultPda] = findVaultPda(marketPda, programId);
const [positionPda] = findPositionPda(marketPda, wallet.publicKey, programId);
// 2. Get orderbook
const orderbookAccount = await connection.getAccountInfo(orderbookPda);
if (!orderbookAccount) throw new Error('Orderbook not found');
const orderbook = parseOrderbook(orderbookAccount.data);
// 3. Find user's orders
const userOrders = [
...orderbook.bids.filter((o) => o.isActive && o.owner.equals(wallet.publicKey)),
...orderbook.asks.filter((o) => o.isActive && o.owner.equals(wallet.publicKey)),
];
console.log('=== Your Orders ===');
for (const order of userOrders) {
const sideNames = ['BuyYes', 'SellYes', 'BuyNo', 'SellNo'];
console.log(
`Order ${order.orderId}: ${sideNames[order.originalSide]} @ ${order.priceBps} bps, qty: ${order.quantity}`
);
}
if (userOrders.length === 0) {
console.log('No open orders');
return;
}
// 4. Cancel first order as example
const orderToCancel = userOrders[0];
console.log(`\nCancelling order ${orderToCancel.orderId}...`);
// Get market for mint
const marketAccount = await connection.getAccountInfo(marketPda);
const market = parseMarket(marketAccount!.data);
const userTokenAccount = await getAssociatedTokenAddress(market.settlementMint, wallet.publicKey);
const cancelIx = createCancelOrderInstruction(
{
market: marketPda,
orderbook: orderbookPda,
position: positionPda,
userTokenAccount,
vault: vaultPda,
user: wallet.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
},
{
orderId: orderToCancel.orderId,
},
programId
);
const tx = new Transaction().add(cancelIx);
const signature = await sendAndConfirmTransaction(connection, tx, [wallet]);
console.log('Order cancelled! Signature:', signature);
}
Example 5: View Position
async function viewPosition(marketId: bigint) {
const [marketPda] = findMarketPda(marketId, programId);
const [positionPda] = findPositionPda(marketPda, wallet.publicKey, programId);
const [marketAccount, positionAccount] = await connection.getMultipleAccountsInfo([
marketPda,
positionPda,
]);
if (!marketAccount) {
console.log('Market not found');
return;
}
if (!positionAccount) {
console.log('No position in this market');
return;
}
const market = parseMarket(marketAccount.data);
const position = parsePosition(positionAccount.data);
console.log('=== Your Position ===');
console.log('YES Shares:', position.yesShares.toString());
console.log('NO Shares:', position.noShares.toString());
console.log('Locked YES:', position.lockedYesShares.toString());
console.log('Locked NO:', position.lockedNoShares.toString());
console.log('Collateral Locked:', position.collateralLocked.toString());
console.log('Settled:', position.settled);
console.log('Payout:', position.payout.toString());
console.log('Active Orders:', position.orderCount);
// Calculate value
const [orderbookPda] = findOrderbookPda(marketPda, programId);
const orderbookAccount = await connection.getAccountInfo(orderbookPda);
if (orderbookAccount) {
const orderbook = parseOrderbook(orderbookAccount.data);
const midPrice = (orderbook.bestBidPrice + orderbook.bestAskPrice) / 2;
const yesValue = (Number(position.yesShares) * midPrice) / 10000;
const noValue = (Number(position.noShares) * (10000 - midPrice)) / 10000;
console.log('\n=== Position Value ===');
console.log('Mid Price:', midPrice, 'bps');
console.log('YES Value:', yesValue.toFixed(2), 'USDC');
console.log('NO Value:', noValue.toFixed(2), 'USDC');
console.log('Total Value:', (yesValue + noValue).toFixed(2), 'USDC');
}
}
Example 6: Settle Position After Resolution
async function settleMyPosition(marketId: bigint) {
const [configPda] = findConfigPda(programId);
const [marketPda] = findMarketPda(marketId, programId);
const [positionPda] = findPositionPda(marketPda, wallet.publicKey, programId);
const [vaultPda] = findVaultPda(marketPda, programId);
// Check market is resolved
const marketAccount = await connection.getAccountInfo(marketPda);
if (!marketAccount) throw new Error('Market not found');
const market = parseMarket(marketAccount.data);
if (market.outcome === 0) {
throw new Error('Market not yet resolved');
}
console.log('Outcome:', market.outcome === 1 ? 'UP' : 'DOWN');
// Check position exists and not settled
const positionAccount = await connection.getAccountInfo(positionPda);
if (!positionAccount) throw new Error('No position found');
const position = parsePosition(positionAccount.data);
if (position.settled) {
console.log('Position already settled');
console.log('Payout was:', position.payout.toString());
return;
}
// Calculate expected payout
const expectedPayout = market.outcome === 1 ? position.yesShares : position.noShares;
console.log('Expected payout:', expectedPayout.toString(), 'USDC');
// Get accounts
const configAccount = await connection.getAccountInfo(configPda);
const config = parseConfig(configAccount!.data);
const userTokenAccount = await getAssociatedTokenAddress(market.settlementMint, wallet.publicKey);
// Build settle instruction
const settleIx = createSettlePositionInstruction(
{
market: marketPda,
position: positionPda,
userTokenAccount,
vault: vaultPda,
user: wallet.publicKey,
cranker: wallet.publicKey, // Self-settle
config: configPda,
treasury: config.treasury,
tokenProgram: TOKEN_PROGRAM_ID,
},
programId
);
const tx = new Transaction().add(settleIx);
const signature = await sendAndConfirmTransaction(connection, tx, [wallet]);
console.log('Position settled! Signature:', signature);
}
Example 7: Monitor Market in Real-Time
async function monitorMarket(marketId: bigint) {
const [marketPda] = findMarketPda(marketId, programId);
const [orderbookPda] = findOrderbookPda(marketPda, programId);
console.log('Monitoring market', marketId.toString());
console.log('Press Ctrl+C to stop\n');
// Subscribe to market changes
const marketSubId = connection.onAccountChange(
marketPda,
(accountInfo) => {
const market = parseMarket(accountInfo.data);
console.log('[Market Update]');
console.log(' Start Price:', market.startPrice.toString());
console.log(' End Price:', market.endPrice.toString());
console.log(
' Outcome:',
market.outcome === 0 ? 'Pending' : market.outcome === 1 ? 'UP' : 'DOWN'
);
},
'confirmed'
);
// Subscribe to orderbook changes
const orderbookSubId = connection.onAccountChange(
orderbookPda,
(accountInfo) => {
const orderbook = parseOrderbook(accountInfo.data);
console.log('[Orderbook Update]');
console.log(' Best Bid:', orderbook.bestBidPrice, 'bps');
console.log(' Best Ask:', orderbook.bestAskPrice, 'bps');
console.log(' Spread:', orderbook.bestAskPrice - orderbook.bestBidPrice, 'bps');
},
'confirmed'
);
// Cleanup on exit
process.on('SIGINT', async () => {
console.log('\nStopping monitor...');
await connection.removeAccountChangeListener(marketSubId);
await connection.removeAccountChangeListener(orderbookSubId);
process.exit(0);
});
// Keep running
await new Promise(() => {});
}
Example 8: Simple Trading Bot
async function simpleBot(marketId: bigint) {
const [marketPda] = findMarketPda(marketId, programId);
const [orderbookPda] = findOrderbookPda(marketPda, programId);
// Configuration
const MAX_POSITION = BigInt(500);
const MIN_TIME_LEFT = 120; // 2 minutes
console.log('Starting simple bot...');
async function tick() {
try {
// Get market state
const [marketAccount, orderbookAccount] = await connection.getMultipleAccountsInfo([
marketPda,
orderbookPda,
]);
if (!marketAccount || !orderbookAccount) {
console.log('Waiting for market...');
return;
}
const market = parseMarket(marketAccount.data);
const orderbook = parseOrderbook(orderbookAccount.data);
// Check if trading
if (market.startPrice === 0n) {
console.log('Trading not started');
return;
}
if (market.endPrice !== 0n) {
console.log('Trading ended');
return;
}
// Check time remaining
const now = Math.floor(Date.now() / 1000);
const timeLeft = Number(market.tEnd) - now;
if (timeLeft < MIN_TIME_LEFT) {
console.log(`Only ${timeLeft}s left, not trading`);
return;
}
// Simple strategy: buy if spread is wide
const spread = orderbook.bestAskPrice - orderbook.bestBidPrice;
if (spread > 400) {
console.log(`Spread ${spread} bps - opportunity!`);
// Check position
const [positionPda] = findPositionPda(marketPda, wallet.publicKey, programId);
const positionAccount = await connection.getAccountInfo(positionPda);
let currentYes = BigInt(0);
if (positionAccount) {
const position = parsePosition(positionAccount.data);
currentYes = position.yesShares;
}
if (currentYes < MAX_POSITION) {
console.log('Placing buy order...');
// Would call buyYesShares here
}
}
} catch (error) {
console.error('Tick error:', error);
}
}
// Run every 10 seconds
setInterval(tick, 10000);
tick();
// Keep running
await new Promise(() => {});
}
Next Steps
- Review API Reference for all endpoints
- See Architecture for system design
- Check Reference for constants and errors