/images/truf-icon.svg Mainnet

Getting Started: Zero to Order Book In 4 Easy Steps (JavaScript)

Fifteen-minute walkthrough for developers to deploy a functional prediction market order book.

Getting Started: Zero to Order Book In 4 Easy Steps (JavaScript)

Welcome! Ready to build something powerful? In this tutorial, we’ll take you from zero to a live, fully functional prediction market order book that uses USDC for trading and settles automatically based on your own data. The best part? You can get this up and running in under 15 minutes using just a few lines of code and at a cost of just a few cents.

We’ll guide you through four simple steps:

  1. Create a Primitive Stream to host your raw data.
  2. Broadcast transactions to populate your stream.
  3. Deploy a Prediction Market Order Book that settles using your data.
  4. Run the code to create your first market.

Token Balance Requirement

Before you begin, ensure your wallet has a sufficient balance of $TRUF tokens. Interacting with TRUF.NETWORK requires $TRUF because all core protocol actions—such as publishing data to the network, requesting attestations, and creating new order books—rely on $TRUF. As the network’s core coordination asset, $TRUF links application-layer activity to protocol-level incentives, ensuring the network functions as intended.

The total network cost for the actions in the code below, at the time of writing, is 103 $TRUF

$TRUF tokens can be acquired from:

Only tokens on Ethereum can be bridged onto TRUF.NETWORK, and bridging can be done at truf.network/account/bridge.

Prerequisites

Before we begin, ensure you have the TRUF.NETWORK SDK installed in your Node.js environment:

npm install @trufnetwork/sdk-js

Step 1: Create Your First Data Stream

A Primitive Stream is a direct data source on TRUF.NETWORK. Think of it as a dedicated ledger for a specific data point, like a commodity price or a weather metric.

In this step, we initialize the client, generate a unique streamID, and deploy the stream to the network.

import { 
	NodeTNClient, 
	StreamId, 
	StreamType,
	decodeMarketData
} from "@trufnetwork/sdk-js";
import { Wallet } from "ethers";

// Initialize your wallet and client
const wallet = new Wallet("YOUR_PRIVATE_KEY");
const client = new NodeTNClient({
    endpoint: "https://gateway.mainnet.truf.network", // Mainnet endpoint
    signerInfo: { address: wallet.address, signer: wallet },
    chainId: "tn-v2.1",
});

async function createStream() {
	// 1. Generate a unique, descriptive Stream ID
	const streamId = await StreamId.generate("predict_test_price_stream");

	// 2. Deploy the stream as a 'Primitive' type
	const deployResult = await client.deployStream(streamId, StreamType.Primitive);

	// 3. Wait for the transaction to be confirmed on-chain
	if (!deployResult.data) {
		throw new Error("Failed to deploy stream");
	}
	await client.waitForTx(deployResult.data.tx_hash);
	console.log(`Stream Deployed! ID: ${streamId.getId()}`);
}

What’s happening: We use StreamId.generate to create a deterministic ID from a string. Crucially, we use waitForTx because TRUF.NETWORK returns success when a transaction enters the mempool; waiting ensures the stream exists before we try to use it.

Be sure to replace "YOUR_PRIVATE_KEY" with the hex string of the private key for your Ethereum wallet.

Step 2: Broadcast Data to Your Stream

Now that your stream is live, you need to populate it with data. We use primitiveAction to insert records. Each record requires an eventTime (Unix timestamp) and a value.

async function broadcastData(streamId) {
	const primitiveAction = client.loadPrimitiveAction();

	// Insert a record (e.g., a price of 50.75)
		const insertTx = await primitiveAction.insertRecord({
		stream: client.ownStreamLocator(streamId),
		eventTime: Math.floor(Date.now() / 1000),
		value: "50.75", // Use strings for precision
	});

	if (insertTx.data) {
		await client.waitForTx(insertTx.data.tx_hash);
		console.log("Data record successfully broadcasted!");
	}
}

What’s happening: The insertRecord method pushes your data to the network. We always pass numeric values as strings to maintain absolute precision across different environments.

Step 3: Create a Prediction Market Order Book

The real power of TRUF.NETWORK comes from using these streams to settle real-world contracts. Here, we create a binary prediction market (e.g., “Will the price be above $X?”) that settles automatically based on the stream data.

async function createMarket(streamId) {
	const orderbook = client.loadOrderbookAction();

	// Define market parameters
	const settleTime = Math.floor(Date.now() / 1000) + (30 * 60); // 30 mins from now
	const threshold = "50.00"; // The 'strike' price for the market

	const marketParams = {
		dataProvider: wallet.address.toLowerCase(),
		streamId: streamId.getId(),
		timestamp: Math.floor(Date.now() / 1000) + 3600,
		threshold: threshold,
		frozenAt: 0,
		bridge: "eth_usdc",
		settleTime: settleTime,
		maxSpread: 10,
		minOrderSize: 1,
	};

	const createResult = await orderbook.createPriceAboveThresholdMarket(marketParams);

	// Wait for the market creation transaction to be confirmed
	if (createResult.data) {
		await client.waitForTx(createResult.data.tx_hash);
		console.log("Prediction Market Created! Hash:", createResult.data.tx_hash);

		// Get all unsettled markets and find the one we just created
		const markets = await orderbook.listMarkets({
			settledFilter: false, // false=unsettled, true=settled, null=all
			limit: 5,
			offset: 0,
		});
		const liveMarkets = await Promise.all(markets.map(async (m) => {
			const market = await orderbook.getMarketInfo(m.id);
			const details = decodeMarketData(market.queryComponents);
			return {
				...m,
				...details
			}
		}));

		// Match the created market based on the parameters we used to create it
		const createdMarket = liveMarkets.find(m => 
			m.dataProvider === marketParams.dataProvider &&
			m.streamId === marketParams.streamId &&
			m.settleTime === marketParams.settleTime &&
			m.thresholds[0] === marketParams.threshold &&
			m.actionId === 'price_above_threshold'
		);

		console.log("Created Market Details:", createdMarket);
		return createdMarket
	}

	return;
}

What’s happening: We use createPriceAboveThresholdMarket, a convenience method that links a specific streamId to a market. When settleTime is reached, the network’s scheduler will automatically poll your stream, request a cryptographic attestation, and distribute payouts to the winners.

Markets are created immediately and trades can begin.

Step 4: Run The Code To Create Your First Market

All that is left is to run the code and, in a few seconds, you will have your own prediction market fully live on TRUF.NETWORK!

(async function () {
	try {
		const streamId = await createStream();
		await broadcastData(streamId);
		await createMarket(streamId);
	} catch (error) {
		console.error("Error:", error);
	}
})();

Next Steps

You’ve just built the backbone of a decentralized oracle and market system! From here, you can explore adding liquidity to your market or creating Composed Streams that aggregate data from multiple sources with weighted averages.

Build out your data broadcasting and market creation strategy to ensure that your markets are fresh and relevant. Be sure to visit Trufscan and add metadata to your data provider and stream entries for maximum discoverability by network participants.

Recent News


Read More