👂Subscribe to Market Updates

When applying trading strategies to markets you need to be able to know your exposure is at any given point in time.

This guide will walk you through setting up a webhook to notify you of changes to Perennial's market & your positions. We'll use this Alchemy's Webhooks, Vercel & Perennial's SDK to achieve this.

Workflow

The workflow for this system has three parts:

  • Notification

  • Process

  • Action

Notification - Alchemy Webhooks

Alchemy's Webhook service lets watch any topic or address on a number of different chains and POST the transaction data to any URL. This is useful for getting realtime changes to the Perennial's markets rather than going by a polling based approach.

In order to setup your webhooks you need to go your Webhook Dashboard:

Once there you can setup a new webhook for testing using the following Subgraph query:

{
  block {
    logs(filter: {addresses: [], topics: ["0x29083474b417ce11b6e16e049302e231f5d3d753484fe3e8155ea0b7ffe4f3c1"]}) {
      data,
      topics,
      account {
        address
      }
    }
  }
}

Note: the topic for our

Once you've entered the query, we need to get a URL to collect the data thats being sent. For development purposes the easiest method is to use Ngrok, a lightweight tunnel to your dev environment. After setting it up, paste the url into the URL section of the webhook.

Process - Vercel

Now we have a service POST'ing data to an endpoint, we need to have a system to receive and process it. For this example we will use Vercel to host the endpoint, however any hosted environment will suffice.

Lets create a script at /api/webhook.ts to receive the webhook calls:

"use server";

export async function POST(req: Request, res: Response) {
	const data = await req.json();
	const logs = data.event.data.block.logs

	// Loop all position updates
	logs.forEach((log) => {
		console.log('New Update: ', log)
	}

	return new Response({status: 200})
}

The script above takes data posted to the endpoint and logs it to the console.

To trigger it you need to modify the URL in the Alchemy Webhook page to match your Ngrok URL and click "Test". 9 times out of 10 this will do nothing.

In order to test, you need to specify which block to run your test on. Modify your Webhook's Subgraph to the following:

{
	block (hash: "0x61dc23440d66afc1e2b1a73fb5c343a467ce0fc0bf4df57c319aba91884af622") {
    logs(filter: {addresses: ["0x61dc23440d66afc1e2b1a73fb5c343a467ce0fc0bf4df57c319aba91884af622"], topics: ["0x29083474b417ce11b6e16e049302e231f5d3d753484fe3e8155ea0b7ffe4f3c1"]}) {
      data,
      topics,
      account {
        address
      }
    }
  }
}

Pressing Test will trigger the webhook as the Subgraph has found a block with logs matching the topic. You should see the transaction's logs in your console.

Lets extend this a little further to make it relevant to your positions:

"use server";

import {
ChainMarkets2,
fetchMarketSnapshots2
} from "perennial-sdk-ts";

// Constants
const bot_address = `0x29E9...E929`
const chainId = 421261 // Arbitrum

// Route handler
export async function POST(req: Request, res: Response) {
	const data = await req.json();
	const logs = data.event.data.block.logs;

	// Keep a track of updated markets
	const markets: string[] = [];
	
	// Loop all position updates
	logs.forEach((log) => {
		// Make a note of the market address
		const market = log.account.address;
		// Convert market address to token symbol
		const code = Object.entries(ChainMarkets2[chainId]).find(
			(x) => x[1].toLowerCase() === market.toLowerCase())?.[0];
		if (!markets.inlcudes(code)) markets.push(code);
	};

	// Fetch the latest state of your positions
	const positions = await fetchMarketSnapshots2(
		publicClient,
		bot_address,
		markets
	);
	console.log(positions)
	
	return new Response({status: 200})
}

The initial script has been modified to take note of the markets effected in the transaction that fired the webhook and then fetch a market position report for your wallet.

Actions

Lets recap where we are:

  • We have a service watching Perennial's markets & calling the endpoint when we position update is submitted.

  • We have an endpoint which receives that data & checks which markets are being updated

  • We have code that calculates your account's for the effected markets

From this point you can trigger code that modifies your position in reaction to the changes.

For some examples of how to get the most out of position data, see here :

  • Check maker exposure & liquidation (if using leverage while making)

  • Check exposure while in a vault

  • Modify exposure - Increase leverage, reduce collateral etc.

Last updated