Query API Reference
All queries are read-only RPC calls using:
connection.getAccountInfo(PDA)
No instruction execution is required.
All accounts are Borsh-encoded and must be decoded using the exact schemas defined earlier.
Configuration Queries
These queries read protocol-level configuration from the 4 Config PDAs.
ConfigCore
PDA
["config"]
Purpose
Global protocol configuration:
- Owner
- Authority
- Fee parameters
- Leverage limits
- Margin settings
- Order counters
- System state (paused flag)
Query Example
const [configCorePDA] = findConfigCoreAddress(PROGRAM_ID);
const accountInfo = await connection.getAccountInfo(configCorePDA);
if (!accountInfo) throw new Error("ConfigCore not found");
const config = ConfigCoreSchema.decode(accountInfo.data);
ConfigAssets
PDA
["config", "assets"]
Purpose
Maps asset name → asset PDA.
Query Example
const [configAssetsPDA] = findConfigAssetsAddress(PROGRAM_ID);
const accountInfo = await connection.getAccountInfo(configAssetsPDA);
const config = ConfigAssetsSchema.decode(accountInfo.data);
Returned structure:
{
is_initialized: bool,
asset_mappings: [
{ name: string, address: PublicKey }
],
bump: u8
}
ConfigPairs
PDA
["config", "pairs"]
Purpose
Stores all registered trading pairs.
Example:
BTC-USD
ETH-USD
Query Example
const [configPairsPDA] = findConfigPairsAddress(PROGRAM_ID);
const accountInfo = await connection.getAccountInfo(configPairsPDA);
const config = ConfigPairsSchema.decode(accountInfo.data);
ConfigKeepers
PDA
["config", "keepers"]
Purpose
Authorized keeper public keys.
Query Example
const [configKeepersPDA] = findConfigKeepersAddress(PROGRAM_ID);
const accountInfo = await connection.getAccountInfo(configKeepersPDA);
const config = ConfigKeepersSchema.decode(accountInfo.data);
Trading Data Queries
Trading data is user-specific.
UserAccount
PDA
["user_account", user, tokenMint]
Purpose
Tracks:
- Balances
- Orders
- Limit orders
- Funding history
- Trading stats
Query Example
const [userAccountPDA] = findUserAccountAddress(
PROGRAM_ID,
userPubkey,
tokenMint
);
const accountInfo = await connection.getAccountInfo(userAccountPDA);
const userAccount = UserAccountSchema.decode(accountInfo.data);
Positions
PDA
["position", user, pair, direction]
direction:
0 = LONG
1 = SHORT
Query Logic
You must check both directions for each pair.
for (const direction of [0, 1]) {
const [positionPDA] = findPositionAddress(
PROGRAM_ID,
userPubkey,
pair,
direction
);
const accountInfo = await connection.getAccountInfo(positionPDA);
if (accountInfo) {
const position = PositionSchema.decode(accountInfo.data);
}
}
Limit Orders
PDA
["limit_order", orderId]
Order IDs are stored in:
userAccount.limit_orders
Query Example
for (const orderId of userAccount.limit_orders) {
const [pda] = findLimitOrderAddress(PROGRAM_ID, orderId);
const accountInfo = await connection.getAccountInfo(pda);
const order = LimitedOrderSchema.decode(accountInfo.data);
}
Deals
PDA
["deal", orderId]
Order IDs are stored in:
userAccount.orders
Query Example
for (const dealId of userAccount.orders) {
const [pda] = findDealAddress(PROGRAM_ID, dealId);
const accountInfo = await connection.getAccountInfo(pda);
const deal = DealSchema.decode(accountInfo.data);
}
Query Execution Flow (User Trading Data)
- Fetch UserAccount
- Extract:
orderslimit_orders
- Fetch:
- Positions (LONG + SHORT per pair)
- Limit Orders
- Deals
- Decode using matching Borsh schemas
Important Notes
- All numeric values are
u128,u64, ori64and should be handled asbigint. - Always normalize BN → bigint after decoding.
- If decoding fails:
- Check schema ordering
- Check account size
- Confirm correct PDA derivation
- Positions exist even if size = 0; check
size > 0to filter active ones.
All queries are deterministic and require no program execution.