Skip to content

Commit

Permalink
Enabled overrides for cfbenchmarks (#3143)
Browse files Browse the repository at this point in the history
* enable overrides for lwba endpoint

* enable overrides for crypto endpoint

* update changeset file

* fix bug with overrides

* move requestTransformer to utils

* remove console.log

---------

Co-authored-by: mmcallister-cll <[email protected]>
  • Loading branch information
karen-stepanyan and mmcallister-cll authored Feb 23, 2024
1 parent efc9d3e commit 3193e6e
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-bottles-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/cfbenchmarks-adapter': patch
---

Enabled request overrides for crypto and crypto-lwba endpoints
24 changes: 6 additions & 18 deletions packages/sources/cfbenchmarks/src/endpoint/crypto-lwba.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { additionalInputValidation, inputParameters } from './crypto'
import { getSecondaryId } from './utils'
import { inputParameters } from './crypto'
import { customInputValidation } from './utils'
import { wsTransport } from '../transport/crypto-lwba'
import { config } from '../config'
import { AdapterRequest } from '@chainlink/external-adapter-framework/util'
import { LwbaEndpoint, LwbaResponseDataFields } from '@chainlink/external-adapter-framework/adapter'
import { requestTransform } from './utils'

export type BaseEndpointTypes = {
// leaving Parameters as crypto inputParameters for backward compatibility
Expand All @@ -12,24 +12,12 @@ export type BaseEndpointTypes = {
Response: LwbaResponseDataFields
}

export const lwbaReqTransformer = (req: AdapterRequest<typeof inputParameters.validated>): void => {
additionalInputValidation(req.requestContext.data)

if (!req.requestContext.data.index) {
req.requestContext.data.index = getSecondaryId(
req.requestContext.data.base as string,
req.requestContext.data.quote as string,
)
}

// Clear base quote to ensure an exact match in the cache with index
delete req.requestContext.data.base
delete req.requestContext.data.quote
}
export const requestTransforms = [requestTransform('crypto-lwba')]

export const endpoint = new LwbaEndpoint({
name: 'crypto-lwba',
transport: wsTransport,
inputParameters: inputParameters,
requestTransforms: [lwbaReqTransformer],
requestTransforms,
customInputValidation,
})
46 changes: 5 additions & 41 deletions packages/sources/cfbenchmarks/src/endpoint/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { CryptoPriceEndpoint } from '@chainlink/external-adapter-framework/adapter'
import { TransportRoutes } from '@chainlink/external-adapter-framework/transports'
import {
AdapterRequest,
SingleNumberResultResponse,
} from '@chainlink/external-adapter-framework/util'
import { AdapterInputError } from '@chainlink/external-adapter-framework/validation/error'
import { SingleNumberResultResponse } from '@chainlink/external-adapter-framework/util'
import { InputParameters } from '@chainlink/external-adapter-framework/validation/input-params'
import { config } from '../config'
import { getIdFromBaseQuote } from './utils'
import { customInputValidation } from './utils'
import { makeRestTransport } from '../transport/crypto-http'
import { makeWsTransport } from '../transport/crypto-ws'
import { requestTransform } from './utils'

export type Params = { index?: string; base?: string; quote?: string }
export type RequestParams = { Params: Params }
Expand Down Expand Up @@ -48,41 +45,7 @@ export type BaseEndpointTypes = {
Response: SingleNumberResultResponse
}

export const additionalInputValidation = ({ index, base, quote }: Params): void => {
// Base and quote must be provided OR index must be provided
if (!(index || (base && quote))) {
const missingInput = !index ? 'index' : 'base /or quote'
throw new AdapterInputError({
statusCode: 400,
message: `Error: missing ${missingInput} input parameters`,
})
}
}

export const cryptoRequestTransform = (
req: AdapterRequest<typeof inputParameters.validated>,
settings: BaseEndpointTypes['Settings'],
): void => {
// TODO: Move additional input validations to proper location after framework supports it
additionalInputValidation(req.requestContext.data)
if (!req.requestContext.data.index) {
const isSecondary = settings.API_SECONDARY
const type = isSecondary ? 'secondary' : 'primary'
// If there is no index set
// we know that base and quote exist from the extra input validation above
// coerce to strings
req.requestContext.data.index = getIdFromBaseQuote(
req.requestContext.data.base as string,
req.requestContext.data.quote as string,
type,
)
}
// Clear base quote to ensure an exact match in the cache with index
delete req.requestContext.data.base
delete req.requestContext.data.quote
}

export const requestTransforms = [cryptoRequestTransform]
export const requestTransforms = [requestTransform('crypto')]

export const endpoint = new CryptoPriceEndpoint({
name: 'crypto',
Expand All @@ -103,4 +66,5 @@ export const endpoint = new CryptoPriceEndpoint({
return req.requestContext.transportName
}
},
customInputValidation,
})
51 changes: 51 additions & 0 deletions packages/sources/cfbenchmarks/src/endpoint/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import { BaseEndpointTypes, inputParameters } from './crypto'
import { AdapterRequest } from '@chainlink/external-adapter-framework/util'
import {
AdapterError,
AdapterInputError,
} from '@chainlink/external-adapter-framework/validation/error'

export const getPrimaryId = (base: string, quote: string): string => `${base}${quote}_RTI`
export const getSecondaryId = (base: string, quote: string): string => `U_${base}${quote}_RTI`

Expand All @@ -8,6 +15,22 @@ type BaseQuoteToIdLookup = { [id: string]: { base: string; quote: string } }
const overridenBaseQuoteFromId: BaseQuoteToIdLookup = {
BRTI: { base: 'BTC', quote: 'USD' },
}

export function customInputValidation(
req: AdapterRequest<typeof inputParameters.validated>,
): AdapterError | undefined {
const { base, quote, index } = req.requestContext.data
// Base and quote must be provided OR index must be provided
if (!(index || (base && quote))) {
const missingInput = !index ? 'index' : 'base /or quote'
throw new AdapterInputError({
statusCode: 400,
message: `Error: missing ${missingInput} input parameters`,
})
}
return
}

export const getBaseQuoteFromId = (id: string): { base: string; quote: string } => {
const override = overridenBaseQuoteFromId[id]
if (override) return override
Expand Down Expand Up @@ -47,3 +70,31 @@ export const getIdFromBaseQuote = (
if (type === 'secondary') return getSecondaryId(base, quote)
return getPrimaryId(base, quote)
}

export function requestTransform(endpoint: string) {
return (
req: AdapterRequest<typeof inputParameters.validated>,
settings: BaseEndpointTypes['Settings'],
) => {
const { base, quote, index } = req.requestContext.data
const rawRequestData = req.body.data
// If `base` in requestContext.data is not the same as in raw request data, it means the value is overriden, use that for index
const baseAliases = ['base', ...inputParameters.definition.base.aliases]
if (baseAliases.every((alias) => base !== rawRequestData[alias])) {
req.requestContext.data.index = base
} else if (!index) {
if (endpoint === 'crypto') {
const isSecondary = settings.API_SECONDARY
const type = isSecondary ? 'secondary' : 'primary'
// If there is no index set
// we know that base and quote exist from the customInputValidation
req.requestContext.data.index = getIdFromBaseQuote(base as string, quote as string, type)
} else if (endpoint === 'crypto-lwba') {
req.requestContext.data.index = getSecondaryId(base as string, quote as string)
}
}
// Clear base quote to ensure an exact match in the cache with index
delete req.requestContext.data.base
delete req.requestContext.data.quote
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ exports[`websocket crypto endpoint should return success 1`] = `
}
`;

exports[`websocket crypto endpoint with override should return success 1`] = `
{
"data": {
"result": 40067,
},
"result": 40067,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 1018,
"providerDataStreamEstablishedUnixMs": 1010,
"providerIndicatedTimeUnixMs": 1645203822000,
},
}
`;

exports[`websocket lwba endpoint should return success 1`] = `
{
"data": {
Expand All @@ -31,3 +46,20 @@ exports[`websocket lwba endpoint should return success 1`] = `
},
}
`;

exports[`websocket lwba endpoint with override should return success 1`] = `
{
"data": {
"ask": 2651.01,
"bid": 2652.26,
"mid": 2651.63,
},
"result": null,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 1018,
"providerDataStreamEstablishedUnixMs": 1010,
"providerIndicatedTimeUnixMs": 1677876163000,
},
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,18 @@ exports[`execute crypto endpoint should return success 1`] = `
},
}
`;

exports[`execute crypto endpoint with override should return success 1`] = `
{
"data": {
"result": 39829.3,
},
"result": 39829.3,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 1641035471111,
"providerDataRequestedUnixMs": 1641035471111,
"providerIndicatedTimeUnixMs": 1645199637000,
},
}
`;
38 changes: 36 additions & 2 deletions packages/sources/cfbenchmarks/test/integration/adapter-ws.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,29 @@ describe('websocket', () => {
const dataCrypto = {
index: 'BRTI',
}
const dataCryptoOverride = {
base: 'ABC',
quote: 'XXX',
overrides: {
cfbenchmarks: {
ABC: 'BRTI',
},
},
}
const dataLwba = {
index: 'U_ETHUSD_RTI',
from: 'ETH',
quote: 'USD',
endpoint: 'cryptolwba',
}
const dataLwbaOverride = {
endpoint: 'cryptolwba',
base: 'LINK',
quote: 'XXX',
overrides: {
cfbenchmarks: {
LINK: 'U_LINKUSD_CHA_RTI',
},
},
}

beforeAll(async () => {
Expand All @@ -41,8 +61,10 @@ describe('websocket', () => {

// Send initial request to start background execute and wait for cache to be filled with results
await testAdapter.request(dataCrypto)
await testAdapter.request(dataCryptoOverride)
await testAdapter.request(dataLwba)
await testAdapter.waitForCache(2)
await testAdapter.request(dataLwbaOverride)
await testAdapter.waitForCache(3)
})

afterAll(async () => {
Expand All @@ -57,6 +79,12 @@ describe('websocket', () => {
const response = await testAdapter.request(dataCrypto)
expect(response.json()).toMatchSnapshot()
})

it('with override should return success', async () => {
const response = await testAdapter.request(dataCryptoOverride)
expect(response.statusCode).toEqual(200)
expect(response.json()).toMatchSnapshot()
})
})

describe('crypto input validation', () => {
Expand All @@ -81,6 +109,12 @@ describe('websocket', () => {
const response = await testAdapter.request(dataLwba)
expect(response.json()).toMatchSnapshot()
})

it('with override should return success', async () => {
const response = await testAdapter.request(dataLwbaOverride)
expect(response.statusCode).toEqual(200)
expect(response.json()).toMatchSnapshot()
})
})

describe('lwba input validation', () => {
Expand Down
17 changes: 17 additions & 0 deletions packages/sources/cfbenchmarks/test/integration/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,22 @@ describe('execute', () => {
expect(response.statusCode).toBe(200)
expect(response.json()).toMatchSnapshot()
})

it('with override should return success', async () => {
const data = {
base: 'XXX',
quote: 'XXX',
transport: 'rest',
overrides: {
cfbenchmarks: {
XXX: 'BRTI',
},
},
}
mockResponseSuccess()
const response = await testAdapter.request(data)
expect(response.statusCode).toBe(200)
expect(response.json()).toMatchSnapshot()
})
})
})
14 changes: 14 additions & 0 deletions packages/sources/cfbenchmarks/test/integration/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ export const mockWebSocketServer = (URL: string): MockWebsocketServer => {
midPrice: '1.1631',
}),
)
} else if (parsed.id === 'U_LINKUSD_CHA_RTI') {
// lwba endpoint
return socket.send(
JSON.stringify({
type: 'rti_stats',
time: 1677876163000,
id: 'U_LINKUSD_CHA_RTI',
value: '2651.63',
utilizedDepth: '1888000.0',
valueAsk: '2651.01',
valueBid: '2652.26',
midPrice: '2651.63',
}),
)
}
})
})
Expand Down

0 comments on commit 3193e6e

Please sign in to comment.