Skip to main content

Overview

The state reader utilities help you fetch and decode the global state of market and escrow apps from the Algorand blockchain. These functions handle the low-level details of:
  • Fetching raw application state from algod/indexer
  • Decoding base64-encoded keys and values
  • Converting byte arrays to Algorand addresses
  • Handling both v2 and v3 API response formats

getMarketGlobalState

Reads the global state of a market app from the chain using the algod client.
import { getMarketGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const algodClient = new algosdk.Algodv2(token, server, port);
const state = await getMarketGlobalState(algodClient, marketAppId);

Parameters

algodClient
Algodv2
required
Algorand algod client instance from the algosdk package
marketAppId
number
required
The market app ID to query

Returns

state
MarketGlobalState
Decoded market global state object

MarketGlobalState Type

type MarketGlobalState = {
  collateral_asset_id: number;      // USDC ASA ID
  yes_asset_id: number;             // YES token ASA ID
  no_asset_id: number;              // NO token ASA ID
  yes_supply: number;               // Total YES tokens minted
  no_supply: number;                // Total NO tokens minted
  is_resolved: number;              // 1 if resolved, 0 otherwise
  is_activated: number;             // 1 if activated, 0 otherwise
  outcome: number;                  // 1 = YES won, 0 = NO won, -1 = not resolved
  resolution_time: number;          // Unix timestamp (seconds)
  fee_base_percent: number;         // Fee base in microunits (e.g., 70000 = 7%)
  fee_timer_threshold: number;      // Fee timer threshold in seconds
  title: string;                    // Market title
  rules: string;                    // Market rules/description
  oracle_address: string;           // Oracle Algorand address
  fee_address: string;              // Fee recipient address
  market_friend_addr: string;       // Market friend address
  escrow_cancel_address: string;    // Escrow cancel address
};

Examples

Basic usage

import { getMarketGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const algodClient = new algosdk.Algodv2(
  '',
  'https://mainnet-api.4160.nodely.io',
  443
);

const marketAppId = 123456789;
const state = await getMarketGlobalState(algodClient, marketAppId);

console.log(`Title: ${state.title}`);
console.log(`YES Asset: ${state.yes_asset_id}`);
console.log(`NO Asset: ${state.no_asset_id}`);
console.log(`Fee Base: ${state.fee_base_percent / 10000}%`);

Check if market is resolved

const state = await getMarketGlobalState(algodClient, marketAppId);

if (state.is_resolved === 1) {
  const winner = state.outcome === 1 ? 'YES' : 'NO';
  console.log(`Market resolved: ${winner} won`);
  console.log(`Winning asset ID: ${winner === 'YES' ? state.yes_asset_id : state.no_asset_id}`);
} else {
  console.log('Market is still open');
  const endDate = new Date(state.resolution_time * 1000);
  console.log(`Resolution time: ${endDate.toLocaleString()}`);
}

Check market liquidity

const state = await getMarketGlobalState(algodClient, marketAppId);

const totalSupply = state.yes_supply + state.no_supply;
console.log(`Total minted: $${(totalSupply / 1_000_000).toFixed(2)}`);
console.log(`YES supply: ${(state.yes_supply / 1_000_000).toFixed(6)} shares`);
console.log(`NO supply: ${(state.no_supply / 1_000_000).toFixed(6)} shares`);

getEscrowGlobalState

Reads the global state of an escrow app via the indexer. Escrow apps represent individual open orders on the orderbook.
import { getEscrowGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const indexerClient = new algosdk.Indexer(token, server, port);
const state = await getEscrowGlobalState(indexerClient, escrowAppId);

Parameters

indexerClient
Indexer
required
Algorand indexer client instance from the algosdk package
escrowAppId
number
required
The escrow app ID to query

Returns

state
EscrowGlobalState
Decoded escrow global state object

EscrowGlobalState Type

type EscrowGlobalState = {
  position?: number;           // 1 = YES, 0 = NO
  side?: number;               // 1 = BUY, 0 = SELL
  price?: number;              // Price in microunits
  quantity?: number;           // Total quantity in microunits
  quantity_filled?: number;    // Filled quantity in microunits
  slippage?: number;           // Slippage in microunits (0 = limit order)
  owner?: string;              // Owner address
  market_app_id?: number;      // Parent market app ID
  asset_listed?: number;       // Listed asset ID
  fee_timer_start?: number;    // Fee timer start timestamp
};

Examples

Read order details

import { getEscrowGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const indexerClient = new algosdk.Indexer(
  '',
  'https://mainnet-idx.4160.nodely.io',
  443
);

const escrowAppId = 987654321;
const state = await getEscrowGlobalState(indexerClient, escrowAppId);

const position = state.position === 1 ? 'YES' : 'NO';
const side = state.side === 1 ? 'BUY' : 'SELL';
const price = (state.price! / 1_000_000).toFixed(2);
const remaining = ((state.quantity! - state.quantity_filled!) / 1_000_000).toFixed(2);

console.log(`${side} ${position} @ $${price}`);
console.log(`Remaining: ${remaining} shares`);
console.log(`Owner: ${state.owner}`);

Check order fill status

const state = await getEscrowGlobalState(indexerClient, escrowAppId);

const total = state.quantity || 0;
const filled = state.quantity_filled || 0;
const fillPercentage = total > 0 ? (filled / total) * 100 : 0;

console.log(`Fill status: ${fillPercentage.toFixed(1)}%`);
console.log(`Filled: ${(filled / 1_000_000).toFixed(2)} shares`);
console.log(`Remaining: ${((total - filled) / 1_000_000).toFixed(2)} shares`);

if (filled === total) {
  console.log('Order fully filled');
} else if (filled > 0) {
  console.log('Order partially filled');
} else {
  console.log('Order unfilled');
}

Determine order type

const state = await getEscrowGlobalState(indexerClient, escrowAppId);

const orderType = (state.slippage || 0) === 0 ? 'LIMIT' : 'MARKET';
console.log(`Order type: ${orderType}`);

if (orderType === 'MARKET') {
  const slippagePct = ((state.slippage! / 1_000_000) * 100).toFixed(2);
  console.log(`Slippage tolerance: ${slippagePct}%`);
}

checkAssetOptIn

Checks if an address has opted into an Algorand Standard Asset (ASA). This is required before an account can receive tokens on Algorand.
import { checkAssetOptIn } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const algodClient = new algosdk.Algodv2(token, server, port);
const isOptedIn = await checkAssetOptIn(algodClient, address, assetId);

Parameters

algodClient
Algodv2
required
Algorand algod client instance from the algosdk package
address
string
required
The Algorand address to check
assetId
number
required
The ASA ID to check (e.g., YES token, NO token, or USDC)

Returns

isOptedIn
boolean
true if the address has opted into the asset, false otherwise

Examples

Check if opted into market tokens

import { checkAssetOptIn, getMarketGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const algodClient = new algosdk.Algodv2(
  '',
  'https://mainnet-api.4160.nodely.io',
  443
);

const address = 'YOUR_ADDRESS_HERE';
const marketAppId = 123456789;

// Get market assets
const state = await getMarketGlobalState(algodClient, marketAppId);

// Check opt-in status
const yesOptedIn = await checkAssetOptIn(algodClient, address, state.yes_asset_id);
const noOptedIn = await checkAssetOptIn(algodClient, address, state.no_asset_id);
const usdcOptedIn = await checkAssetOptIn(algodClient, address, state.collateral_asset_id);

console.log(`YES token opt-in: ${yesOptedIn}`);
console.log(`NO token opt-in: ${noOptedIn}`);
console.log(`USDC opt-in: ${usdcOptedIn}`);

Validate before trading

import { checkAssetOptIn, getMarketGlobalState } from '@alpha-arcade/sdk';

const validateMarketAccess = async (
  algodClient: algosdk.Algodv2,
  address: string,
  marketAppId: number
): Promise<{ canTrade: boolean; missingAssets: string[] }> => {
  const state = await getMarketGlobalState(algodClient, marketAppId);
  const missingAssets: string[] = [];

  const usdcOptedIn = await checkAssetOptIn(algodClient, address, state.collateral_asset_id);
  if (!usdcOptedIn) missingAssets.push('USDC');

  const yesOptedIn = await checkAssetOptIn(algodClient, address, state.yes_asset_id);
  if (!yesOptedIn) missingAssets.push('YES');

  const noOptedIn = await checkAssetOptIn(algodClient, address, state.no_asset_id);
  if (!noOptedIn) missingAssets.push('NO');

  return {
    canTrade: missingAssets.length === 0,
    missingAssets
  };
};

// Usage
const validation = await validateMarketAccess(algodClient, userAddress, marketAppId);
if (!validation.canTrade) {
  console.log(`Please opt-in to: ${validation.missingAssets.join(', ')}`);
} else {
  console.log('Ready to trade!');
}

Batch check multiple assets

const checkMultipleAssets = async (
  algodClient: algosdk.Algodv2,
  address: string,
  assetIds: number[]
): Promise<Map<number, boolean>> => {
  const results = new Map<number, boolean>();
  
  await Promise.all(
    assetIds.map(async (assetId) => {
      const isOptedIn = await checkAssetOptIn(algodClient, address, assetId);
      results.set(assetId, isOptedIn);
    })
  );
  
  return results;
};

// Check multiple markets at once
const assetIds = [31566704, 987654321, 987654322]; // USDC, YES, NO
const optInStatus = await checkMultipleAssets(algodClient, address, assetIds);

optInStatus.forEach((isOptedIn, assetId) => {
  console.log(`Asset ${assetId}: ${isOptedIn ? 'opted in' : 'not opted in'}`);
});

decodeGlobalState

Low-level utility that decodes raw global state arrays from Algorand into JavaScript objects. This function handles base64 decoding and type conversion automatically.
Most users should use getMarketGlobalState or getEscrowGlobalState instead, which call this function internally. Use decodeGlobalState directly only if you need custom state decoding logic.
import { decodeGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const algodClient = new algosdk.Algodv2(token, server, port);
const appInfo = await algodClient.getApplicationByID(appId).do();
const rawState = appInfo['params']['global-state'] || appInfo.params?.globalState;

const decoded = decodeGlobalState(rawState);

Parameters

rawState
any[]
required
Raw global-state array from algod or indexer API response

Returns

state
Record<string, any>
Decoded key-value object with:
  • String keys decoded from base64
  • Number values for integers
  • Algorand addresses for 32-byte values in address fields
  • Raw bytes for other byte values

How It Works

The function performs these transformations:
  1. Key decoding: Base64-encoded keys → UTF-8 strings
  2. Type handling:
    • Type 1 (bytes) → Algorand address if 32 bytes and address field, otherwise raw bytes
    • Type 2 (uint) → JavaScript number
  3. Address recognition: Automatically converts 32-byte values in fields like owner, oracle_address, fee_address, etc. to Algorand addresses

Example

import { decodeGlobalState } from '@alpha-arcade/sdk';
import algosdk from 'algosdk';

const algodClient = new algosdk.Algodv2('', 'https://mainnet-api.algonode.cloud', 443);

// Get raw app state
const appInfo = await algodClient.getApplicationByID(3012345678).do();
const rawState = appInfo.params['global-state'] || appInfo.params?.globalState;

// Decode it
const state = decodeGlobalState(rawState);

console.log(state.title); // "Will BTC reach $100k by EOY?"
console.log(state.yes_asset_id); // 123456789
console.log(state.oracle_address); // "ALGO_ADDRESS..."
This function handles both v2 (kebab-case: global-state) and v3 (camelCase: globalState) API formats automatically.

Error Handling

All state reader functions may throw errors if:
  • The app ID does not exist
  • The network request fails
  • The app state is malformed
Always wrap calls in try-catch blocks:
try {
  const state = await getMarketGlobalState(algodClient, marketAppId);
  console.log(state.title);
} catch (error) {
  console.error('Failed to fetch market state:', error);
  // Handle error (e.g., show user message, retry, etc.)
}

API Version Compatibility

These utilities handle both v2 (kebab-case) and v3 (camelCase) Algorand API response formats automatically:
  • v2: global-state, asset-id
  • v3: globalState, assetId
You don’t need to worry about which API version you’re using — the functions will work with both.

Build docs developers (and LLMs) love