Skip to main content

Installation

First, we install kuru-sdk
npm i @kuru-labs/kuru-sdk

Configure environment

Export your PRIVATE_KEY to use the examples
export PRIVATE_KEY=<your_private_key>
Never expose your private keys in your code, especially if the code is stored in version control systems accessible by others or if it’s deployed to shared or public servers.

Update config.json

config.json
{   
	"rpcUrl": "monad_rpc_url",    
	"marginAccountAddress": "0xdDDaBd30785bA8b45e434a1f134BDf304d6125d9", // testnet   
	"routerAddress": "0x1f5A250c4A506DA4cE584173c6ed1890B1bf7187", // testnet
}

Deposit into margin account

// Example: deposit tokens into a margin account via Kuru SDK
// Fill placeholders (rpcUrl, marginAccountAddress, tokenAddress, amount, decimals)
// and export PRIVATE_KEY before running.
import { ethers } from "ethers";
import * as KuruSdk from "@kuru-labs/kuru-sdk";
import * as KuruConfig from "../config.json";

const {rpcUrl, marginAccountAddress} = KuruConfig;
const tokenAddress = "";            // TODO: ERC-20 token to deposit (use 0x000...000 for native if supported)
const amount = "";                  // TODO: human amount as string (e.g., "1000")
const decimals = 18;                // TODO: token decimals (e.g., 18 for ABC, 6 for USDC)

async function main() {
  const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
  const privateKey = process.env.PRIVATE_KEY; // must be set in env
  if (!privateKey) throw new Error("PRIVATE_KEY environment variable not set");
  const signer = new ethers.Wallet(privateKey, provider);

  try {
    // Deposits on behalf of the signer address. Set a different receiver if desired
    const receipt = await KuruSdk.MarginDeposit.deposit(
      signer,
      marginAccountAddress,
      await signer.getAddress(),
      tokenAddress,
      amount,
      decimals,
      true // set to true to auto-approve ERC-20 if not already approved
    );
    console.log("Transaction hash:", receipt.transactionHash);
  } catch (error) {
    console.error("Error depositing:", error);
  }
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Place a limit buy

Placing a limit order. This consumes funds in your margin account.
import parseEvents for tracking orders created.
parseEvents
import { ethers, BigNumber } from 'ethers';

interface TradeInfo {
    orderId: BigNumber;
    filledSize: BigNumber;
    price: BigNumber;
    isBuy: boolean;
}

export async function parseEvents(receipt: ethers.ContractReceipt): Promise<{
    newOrderIds: BigNumber[];
    trades: TradeInfo[];
}> {
    const newOrderIds: BigNumber[] = [];
    const trades: TradeInfo[] = [];

    receipt.logs.forEach((log) => {
        if (log.topics[0] === ethers.utils.id("OrderCreated(uint40,address,uint96,uint32,bool)")) {
            try {
                const decodedLog = ethers.utils.defaultAbiCoder.decode(
                    ['uint40', 'address', 'uint96', 'uint32', 'bool'],
                    log.data
                );
                const orderId = BigNumber.from(decodedLog[0]);
                newOrderIds.push(orderId);
            } catch (error) {
                console.error("Error decoding OrderCreated event:", error);
            }
        } else if (log.topics[0] === ethers.utils.id("Trade(uint40,address,bool,uint256,uint96,address,address,uint96)")) {
            try {
                const decodedLog = ethers.utils.defaultAbiCoder.decode(
                    ['uint40', 'address', 'bool', 'uint256', 'uint96', 'address', 'address', 'uint96'],
                    log.data
                );
                trades.push({
                    orderId: BigNumber.from(decodedLog[0]),
                    price: BigNumber.from(decodedLog[3]),
                    filledSize: BigNumber.from(decodedLog[7]),
                    isBuy: decodedLog[2]
                });
            } catch (error) {
                console.error("Error decoding trade event:", error);
            }
        }
    });

    return { newOrderIds, trades };
}
// Example: place a limit buy order using the Kuru SDK
// Fill the placeholders (rpcUrl, marketAddress) and export PRIVATE_KEY before running.
import { ethers } from "ethers";
import * as KuruSdk from "@kuru-labs/kuru-sdk";
import { parseEvents } from "./";
import * as KuruConfig from "../config.json";

const {rpcUrl, marginAccountAddress} = KuruConfig;
 
// Order parameters (strings OK; SDK handles parsing/decimals):
// price → quoted in quote per base (e.g., USDC per ABC); must respect tick size
// size  → amount of base to buy; must be ≥ min size
const price = ""; // TODO: e.g., "5" for 5 USDC per ABC
const size = "";  // TODO: e.g., "10" for 10 ABC
 
async function main() {
    const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
    // PRIVATE_KEY should be exported in your shell before running
    const privateKey = process.env.PRIVATE_KEY; // must be set in env
    if (!privateKey) throw new Error("PRIVATE_KEY environment variable not set");
    const signer = new ethers.Wallet(privateKey, provider);
 
    // Fetch market parameters (precisions, tick size, fees)
    const marketParams = await KuruSdk.ParamFetcher.getMarketParams( 
        provider, 
        marketAddress
    );
    try { 
        // Place a Good-Till-Cancel limit buy
        const receipt = await KuruSdk.GTC.placeLimit(   
            signer,   
            marketAddress,   
            marketParams,   
            {   
                price,   
                size,   
                isBuy: true,   
                postOnly: true
            }   
        );   
        console.log("Transaction hash:", receipt.transactionHash); 
        // Extract created order ids from events
        const { newOrderIds } = await parseEvents(receipt)  
        console.log("OrderIds:", newOrderIds)  
    } catch (error) {
        console.error("Error placing limit buy order:", error);
    }
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Next steps

Now that you have a basic set up in place, read all the functionality of the SDK: Order book Router