Querying the Market

It's time to get familiar with the market contract itself. The market QueryMsg provides a number of different queries. But we're going to start off by looking at two queries that provide protocol-wide information:

  • status provides information on the current status of the market: configuration values, available liquidity, notional interest, and more.
  • spot_price gives the price at a given timestamp or, if no timestamp is provided, at the current time.
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";

// Testnet factory address
const factoryAddress =
  "osmo1ymuvx9nydujjghgxxug28w48ptzcu9ysvnynqdw78qgteafj0syq247w5u"

// Osmosis testnet RPC endpoint
// retrieved from https://github.com/cosmos/chain-registry/blob/aecb225b17d1cb5a3826887735cafeb7e62934d0/testnets/osmosistestnet/chain.json#L123
const rpcEndpoint = "https://rpc.osmotest5.osmosis.zone"

const runAll = async () => {
  const client = await CosmWasmClient.connect(rpcEndpoint);

  const { market_addr: marketAddress } = await client.queryContractSmart(
    factoryAddress,
    {
      market_info: { market_id: "ATOM_USD" },
    }
  );

  const price = await client.queryContractSmart(marketAddress, {
    spot_price: {},
  });
  console.log(JSON.stringify(price));

  const status = await client.queryContractSmart(marketAddress, { status: {} });
  console.log(JSON.stringify(status));
};

runAll();

This demonstrates a common theme you'll have in your own code: use the factory to get the market address, and then proceed to query that market. For brevity in the rest of the tutorial, we'll simply hard-code the market address.

Spot price

Let's look at the price data, prettied up a bit:

{
  "price_notional":"0.080100999350080516",
  "price_usd":"12.48423875",
  "price_base":"12.48423875",
  "timestamp":"1709569578000000000",
  "is_notional_usd":true,
  "market_type":"collateral_is_base",
}

Let's start with the market_type. Our ATOM_USD market is a collateral-is-base market, meaning that we use ATOM as the collateral asset. We'll see in later sections how to get some ATOM to experiment with and how to use it with the market contract.

The timestamp field is given in nanoseconds since the epoch. You can use any epoch converter to translate into human-readable dates; epochconverter.com is a good choice. The above timestamp comes out to Monday, March 4, 2024 16:39:51 GMT.

price_base gives the price of the base asset (ATOM) in terms of the quote asset (USD). This is the standard price you're used to seeing. price_usd gives the price of the collateral asset in terms of USD. In this market, price_usd will always give the same value, since ATOM is both the base and collateral assets, and USD is the quote asset. price_notional is the price used internally by the system. For more information on how Levana Perps handles collateral-is-base markets internally, see our collateral is base slide deck.

Status

The status response provides a lot of information, and we aren't going to look at it all right now. Let's instead start with a subset of the data:

{
  "market_id":"ATOM_USD",
  "base":"ATOM",
  "quote":"USD",
  "market_type":"collateral_is_base",
  "collateral": {
    "cw20": {
      "addr":"osmo1g68w56vq9q0vr2mdlzp2l80j0lelnffkn7y3zhek5pavtxzznuks8wkv6k",
      "decimal_places": 6
    }

  },
  "liquidity": {
    "locked":"297436.161968789588197153",
    "unlocked":"90564.995625182297950879",
    "total_lp":"261441.162273575907212688",
    "total_xlp":"130064.659093487869092113"

  },
  "borrow_fee":"0.01",
  "borrow_fee_lp":"0.005465354312584584",
  "borrow_fee_xlp":"0.004534645687415416",
  "long_funding":"-0.069789280603992498",
  "short_funding":"0.067865306914332403",
  "long_notional":"2659830.714669499436727636",
  "short_notional":"2735236.611240979886379068",
  "long_usd":"2659830.714669499436727636",
  "short_usd":"2735236.611240979886379068",
}

We start off with an overview of the market metadata itself: the market ID, base and quote assets, and whether market_type is collateral_is_base or collateral_is_quote. Next we get to the collateral itself. The above data says that we're using a CW20 token contract with the given address. Levana Perps supports both CW20s and native coins as collateral assets.

Next we see the liquidity section, which provides an overview of liquidity provided to the platform. The values locked and unlocked give the total amount of collateral available in the system. locked is the total collateral currently locked in positions to guarantee solvency if a trader takes profits. unlocked represents liquidity available for traders to lock up in new positions. total_lp and total_xlp give the total number of LP and xLP tokens.

borrow_fee, long_funding, and short_funding are all ratios giving annualized rates for these values. For example, above, a trader would pay approximately 12.8% APR on any funds they borrow in a position.

long_notional and short_notional represent the long and short notional interest, or the sum of all long and short position sizes currently open. An overall goal of Levana Perps is to keep the net notional, which is net_notional = long_notional - short_notional, as close to 0 as possible. And finally, long_usd and short_usd represent the same values, but converted to USD. In our ATOM_USD market, the notional interest is already expressed in USD, so the values are the same as long_notional and short_notional. But in other markets, like stablecoin-denominated markets, this won't be the case.

We could continue querying the market, but it's much more interesting to begin interacting with it. To do that, we'll need a wallet with some funds. Let's take a detour from the code and get that set up.