Skip to content

Commit

Permalink
NYFED (#3607)
Browse files Browse the repository at this point in the history
* NYFED

* Rename input
  • Loading branch information
mxiao-cll authored Dec 6, 2024
1 parent 02f8e15 commit 0e6e3d8
Show file tree
Hide file tree
Showing 19 changed files with 340 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-phones-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/nyfed-adapter': major
---

NYFED
20 changes: 20 additions & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.
3 changes: 3 additions & 0 deletions packages/sources/nyfed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Chainlink External Adapter for nyfed

This README will be generated automatically when code is merged to `main`. If you would like to generate a preview of the README, please run `yarn generate:readme nyfed`.
40 changes: 40 additions & 0 deletions packages/sources/nyfed/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@chainlink/nyfed-adapter",
"version": "0.0.0",
"description": "Chainlink nyfed adapter.",
"keywords": [
"Chainlink",
"LINK",
"blockchain",
"oracle",
"nyfed"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"repository": {
"url": "https://github.com/smartcontractkit/external-adapters-js",
"type": "git"
},
"license": "MIT",
"scripts": {
"clean": "rm -rf dist && rm -f tsconfig.tsbuildinfo",
"prepack": "yarn build",
"build": "tsc -b",
"server": "node -e 'require(\"./index.js\").server()'",
"server:dist": "node -e 'require(\"./dist/index.js\").server()'",
"start": "yarn server:dist"
},
"devDependencies": {
"@types/jest": "27.5.2",
"@types/node": "16.18.119",
"nock": "13.5.5",
"typescript": "5.6.3"
},
"dependencies": {
"@chainlink/external-adapter-framework": "1.7.4",
"tslib": "2.4.1"
}
}
9 changes: 9 additions & 0 deletions packages/sources/nyfed/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AdapterConfig } from '@chainlink/external-adapter-framework/config'

export const config = new AdapterConfig({
API_ENDPOINT: {
description: 'An API endpoint for Data Provider',
type: 'string',
default: 'https://markets.newyorkfed.org/api/rates/secured/all/latest.json',
},
})
1 change: 1 addition & 0 deletions packages/sources/nyfed/src/endpoint/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { endpoint as rate } from './rate'
32 changes: 32 additions & 0 deletions packages/sources/nyfed/src/endpoint/rate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
import { SingleNumberResultResponse } from '@chainlink/external-adapter-framework/util'
import { config } from '../config'
import { httpTransport } from '../transport/rate'

export const inputParameters = new InputParameters(
{
symbol: {
required: true,
type: 'string',
description: 'Symbol of the rate you are looking for',
},
},
[
{
symbol: 'SOFR',
},
],
)

export type BaseEndpointTypes = {
Parameters: typeof inputParameters.definition
Response: SingleNumberResultResponse
Settings: typeof config.settings
}

export const endpoint = new AdapterEndpoint({
name: 'rate',
transport: httpTransport,
inputParameters,
})
21 changes: 21 additions & 0 deletions packages/sources/nyfed/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
import { Adapter } from '@chainlink/external-adapter-framework/adapter'
import { config } from './config'
import { rate } from './endpoint'

export const adapter = new Adapter({
defaultEndpoint: rate.name,
name: 'NYFED',
config,
endpoints: [rate],
rateLimiting: {
tiers: {
default: {
rateLimit1m: 6,
note: 'Reasonable limits',
},
},
},
})

export const server = (): Promise<ServerInstance | undefined> => expose(adapter)
72 changes: 72 additions & 0 deletions packages/sources/nyfed/src/transport/rate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { HttpTransport } from '@chainlink/external-adapter-framework/transports'
import { BaseEndpointTypes } from '../endpoint/rate'

export interface ResponseSchema {
refRates: {
effectiveDate: string
type: string
percentRate?: number
}[]
}

export type HttpTransportTypes = BaseEndpointTypes & {
Provider: {
RequestBody: never
ResponseBody: ResponseSchema
}
}
export const httpTransport = new HttpTransport<HttpTransportTypes>({
prepareRequests: (params, config) => {
return params.map((param) => {
return {
params: [param],
request: {
baseURL: config.API_ENDPOINT,
},
}
})
},
parseResponse: (params, response) => {
if (!response.data) {
return params.map((param) => {
return {
params: param,
response: {
errorMessage: `The data provider didn't return any value`,
statusCode: 502,
},
}
})
}

return params.map((param) => {
const result = response.data.refRates.find(
(d) => d.type.toUpperCase() == param.symbol.toUpperCase(),
)
if (result?.percentRate == undefined) {
return {
params: param,
response: {
errorMessage: `The data provider didn't return any value for ${param.symbol}`,
statusCode: 502,
},
}
} else {
return {
params: param,
response: {
result: result.percentRate,
data: {
result: result.percentRate,
},
timestamps: {
providerIndicatedTimeUnixMs: result.effectiveDate
? new Date(result.effectiveDate).getTime()
: undefined,
},
},
}
}
})
},
})
5 changes: 5 additions & 0 deletions packages/sources/nyfed/test-payload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"requests": [{
"symbol": "SOFR"
}]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`execute rate endpoint should return success 1`] = `
{
"data": {
"result": 4.59,
},
"result": 4.59,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 978347471111,
"providerDataRequestedUnixMs": 978347471111,
"providerIndicatedTimeUnixMs": 1733356800000,
},
}
`;
45 changes: 45 additions & 0 deletions packages/sources/nyfed/test/integration/adapter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
TestAdapter,
setEnvVariables,
} from '@chainlink/external-adapter-framework/util/testing-utils'
import * as nock from 'nock'
import { mockResponseSuccess } from './fixtures'

describe('execute', () => {
let spy: jest.SpyInstance
let testAdapter: TestAdapter
let oldEnv: NodeJS.ProcessEnv

beforeAll(async () => {
oldEnv = JSON.parse(JSON.stringify(process.env))
process.env.API_ENDPOINT = 'http://fake-url'

const mockDate = new Date('2001-01-01T11:11:11.111Z')
spy = jest.spyOn(Date, 'now').mockReturnValue(mockDate.getTime())

const adapter = (await import('./../../src')).adapter
adapter.rateLimiting = undefined
testAdapter = await TestAdapter.startWithMockedCache(adapter, {
testAdapter: {} as TestAdapter<never>,
})
})

afterAll(async () => {
setEnvVariables(oldEnv)
await testAdapter.api.close()
nock.restore()
nock.cleanAll()
spy.mockRestore()
})

describe('rate endpoint', () => {
it('should return success', async () => {
mockResponseSuccess()
const response = await testAdapter.request({
symbol: 'SOFR',
})
expect(response.statusCode).toBe(200)
expect(response.json()).toMatchSnapshot()
})
})
})
36 changes: 36 additions & 0 deletions packages/sources/nyfed/test/integration/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import nock from 'nock'

export const mockResponseSuccess = (): nock.Scope =>
nock('http://fake-url', {
encodedQueryParams: true,
})
.get('/')
.reply(
200,
() => ({
refRates: [
{
effectiveDate: '2024-12-05',
type: 'SOFR',
percentRate: 4.59,
percentPercentile1: 4.55,
percentPercentile25: 4.57,
percentPercentile75: 4.65,
percentPercentile99: 4.68,
volumeInBillions: 2325,
revisionIndicator: '',
},
],
}),
[
'Content-Type',
'application/json',
'Connection',
'close',
'Vary',
'Accept-Encoding',
'Vary',
'Origin',
],
)
.persist()
9 changes: 9 additions & 0 deletions packages/sources/nyfed/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*", "src/**/*.json"],
"exclude": ["dist", "**/*.spec.ts", "**/*.test.ts"]
}
7 changes: 7 additions & 0 deletions packages/sources/nyfed/tsconfig.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src/**/*", "**/test", "src/**/*.json"],
"compilerOptions": {
"noEmit": true
}
}
3 changes: 3 additions & 0 deletions packages/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@
{
"path": "./sources/nikkei"
},
{
"path": "./sources/nyfed"
},
{
"path": "./sources/oanda"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/tsconfig.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@
{
"path": "./sources/nikkei/tsconfig.test.json"
},
{
"path": "./sources/nyfed/tsconfig.test.json"
},
{
"path": "./sources/oanda/tsconfig.test.json"
},
Expand Down
13 changes: 13 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4922,6 +4922,19 @@ __metadata:
languageName: unknown
linkType: soft

"@chainlink/nyfed-adapter@workspace:packages/sources/nyfed":
version: 0.0.0-use.local
resolution: "@chainlink/nyfed-adapter@workspace:packages/sources/nyfed"
dependencies:
"@chainlink/external-adapter-framework": "npm:1.7.4"
"@types/jest": "npm:27.5.2"
"@types/node": "npm:16.18.119"
nock: "npm:13.5.5"
tslib: "npm:2.4.1"
typescript: "npm:5.6.3"
languageName: unknown
linkType: soft

"@chainlink/oanda-adapter@workspace:packages/sources/oanda":
version: 0.0.0-use.local
resolution: "@chainlink/oanda-adapter@workspace:packages/sources/oanda"
Expand Down

0 comments on commit 0e6e3d8

Please sign in to comment.