The RFQ channel is where a user will either publish/streama RFQ. The user who is publishing a RFQ is the requester for a quote. They are considered the "taker" in the transaction request. The user who is streamingfor RFQ's is the provider of the quote. They are considered the "maker" of the quote.
It is important to note that the RFQ channel is not where RFQ quotes are actually generated or filled. It is only used to broadcast & listen to requests.
When an actual quote is generated by the quote provider, it can only be seen on the Quote channel. So if you intend to publish on the RFQ Channel, you will need to stream on the Quote Channel to see quotes that are returned to you.
The quote provider who is streaming on the RFQ Channel will respond to request by posting the quotes via rest api.
Responding to RFQ (RFQ Streamers Only)
If you are a streamer of RFQ's you will need to produce quote objects and post them via REST API. When doing so, the quotes must have the takerAddress populated with the requesters address. This is an optional param when posting quotes via REST API. If it is intentionally omitted when posting a quote, the order is considered PUBLIC and can be filled by anyone.
/*
TypeScript Sample Code
NOTE: since this is an API, WS logic can be written in any language. This example
is in typescript, but the overall sequence will be the same for any language.
*/
import { RawData, WebSocket } from 'ws'
// Example for for local container runtime
const url = `ws://localhost:${process.env.HTTP_PORT}`
const wsConnection = new WebSocket(url)
const MOCK_API_KEY = '3423ee2bfd89491f82b351404'
const authMessage: AuthMessage = {
type: 'AUTH',
apiKey: MOCK_API_KEY,
body: null
}
// send AuthMessage
wsConnection.send(JSON.stringify(authMsg))
// IMPORTANT!!! published RFQ messages must be in web3 format
const rfqRequest = {
type: 'RFQ',
body: {
poolKey: {
base: '0x7F5bc2250ea57d8ca932898297b1FF9aE1a04999'
quote: '0x53421DB1f41368E028A4239954feB5033C7B3729'
oracleAdapter: string
strike: parseEther('1700').toString()
maturity: 1702022400
isCallPool: boolean
},
side: 'ask',
chainId: '421613', // or '42161' for prod environment
size: parseEther('1').toString(),
taker: '0x3D1dcc44D65C08b39029cA8673D705D7e5c4cFF2'
}
}
const wsCallback = (data: RawData) => {
const message: InfoMessage | ErrorMessage | RFQMessage | PostQuoteMessage | FillQuoteMessage | DeleteQuoteMessage = JSON.parse(data.toString())
switch (message.type) {
case 'INFO': {
// auth result message will arrive here
break
}
case 'ERROR': {
// any error message will arrive here
break
}
default: {
throw `Unexpected message type ${message.type}`
}
}
// subscribe to WS messages
wsConnection.on('message', wsCallback)
// publish RFQMessage to start getting quotes streamed on QUOTES channel
wsConnection.send(JSON.stringify(rfqRequest))
// unsubscribe to WS messages
// NOTE: unsubscribing does NOT close the ws connection
const unsubscribeMsg: WSUnsubscribeMessage = {
type: 'UNSUBSCRIBE',
channel: channel,
body: null,
}
wsConnection.send(JSON.stringify(unsubscribeMsg))
/*
TypeScript Sample Code
NOTE: since this is an API, WS logic can be written in any language. This example
is in typescript, but the overall sequence will be the same for any language.
*/
import { RawData, WebSocket } from 'ws'
// Example for for local container runtime
const url = `ws://localhost:${process.env.HTTP_PORT}`
const wsConnection = new WebSocket(url)
const MOCK_API_KEY = '3423ee2bfd89491f82b351404'
const authMessage: AuthMessage = {
type: 'AUTH',
apiKey: MOCK_API_KEY,
body: null
}
// send AuthMessage
wsConnection.send(JSON.stringify(authMsg))
const webSocketFilter: FilterMessage = {
type: 'FILTER',
channel: 'RFQ',
body: {
chainId: '42161',
taker: '0x170f9e3eb81ed29491a2efdcfa2edd34fdd24a71' // fake address
}
}
const wsCallback = (data: RawData) => {
const message: InfoMessage | ErrorMessage | RFQMessage | PostQuoteMessage | FillQuoteMessage | DeleteQuoteMessage = JSON.parse(data.toString())
switch (message.type) {
case 'INFO': {
// auth result message will arrive here
break
}
case 'RFQ': {
// streamed requests will arrive here
// business logic to POST quote via REST API HERE
}
case 'ERROR': {
// any error message will arrive here
break
}
default: {
throw `Unexpected message type ${message.type}`
}
}
// subscribe to WS messages
wsConnection.on('message', wsCallback)
// send FilterMessage to start listening to RFQ stream
wsConnection.send(JSON.stringify(webSocketFilter))
interface AuthMessage {
type: 'AUTH'
apiKey: string
body: null
}
// INFO message from Premia orderbook
interface InfoMessage {
type: 'INFO'
body: null
message: string
}
// ERROR message from Premia orderbook
interface ErrorMessage {
type: 'ERROR'
body: null
message: string
}
// human-readable format of a RFQ request
interface RFQMessage {
type: 'RFQ'
body: {
base: string // base token name i.e. WETH
quote: string // base token name i.e. USDC
expiration: string // i.e. 23NOV2023
strike: number
type: 'C' | 'P'
side: 'bid' | 'ask'
size: number
taker: string
}
}
// Unsubscribe message
interface WSUnsubscribeMessage {
type: 'UNSUBSCRIBE'
channel: 'QUOTES' | 'RFQ'
body: null
}