From e5232aefd9fa399a6b6a6bd6b558d83356243aa9 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 28 Jan 2021 13:35:40 -0600 Subject: [PATCH 1/4] Add dxfee-secondary --- .github/strategy/adapters.json | 1 + dxfeed-secondary/.eslintrc.js | 3 ++ dxfeed-secondary/README.md | 44 +++++++++++++++++ dxfeed-secondary/package.json | 47 ++++++++++++++++++ dxfeed-secondary/src/adapter.ts | 36 ++++++++++++++ dxfeed-secondary/src/config.ts | 6 +++ dxfeed-secondary/src/endpoint/index.ts | 1 + dxfeed-secondary/src/endpoint/price.ts | 30 ++++++++++++ dxfeed-secondary/src/index.ts | 7 +++ dxfeed-secondary/test/adapter.test.ts | 66 ++++++++++++++++++++++++++ dxfeed-secondary/tsconfig.json | 10 ++++ dxfeed/.eslintrc.js | 4 +- dxfeed/adapter.js | 59 ----------------------- dxfeed/index.js | 4 -- dxfeed/package.json | 40 ++++++++++++++-- dxfeed/src/adapter.ts | 36 ++++++++++++++ dxfeed/src/config.ts | 6 +++ dxfeed/src/endpoint/index.ts | 1 + dxfeed/src/endpoint/price.ts | 61 ++++++++++++++++++++++++ dxfeed/src/index.ts | 7 +++ dxfeed/test/adapter.test.ts | 66 ++++++++++++++++++++++++++ dxfeed/test/adapter_test.js | 62 ------------------------ dxfeed/tsconfig.json | 10 ++++ package.json | 1 + 24 files changed, 477 insertions(+), 131 deletions(-) create mode 100644 dxfeed-secondary/.eslintrc.js create mode 100644 dxfeed-secondary/README.md create mode 100644 dxfeed-secondary/package.json create mode 100644 dxfeed-secondary/src/adapter.ts create mode 100644 dxfeed-secondary/src/config.ts create mode 100644 dxfeed-secondary/src/endpoint/index.ts create mode 100644 dxfeed-secondary/src/endpoint/price.ts create mode 100644 dxfeed-secondary/src/index.ts create mode 100644 dxfeed-secondary/test/adapter.test.ts create mode 100644 dxfeed-secondary/tsconfig.json delete mode 100644 dxfeed/adapter.js delete mode 100644 dxfeed/index.js create mode 100644 dxfeed/src/adapter.ts create mode 100644 dxfeed/src/config.ts create mode 100644 dxfeed/src/endpoint/index.ts create mode 100644 dxfeed/src/endpoint/price.ts create mode 100644 dxfeed/src/index.ts create mode 100644 dxfeed/test/adapter.test.ts delete mode 100644 dxfeed/test/adapter_test.js create mode 100644 dxfeed/tsconfig.json diff --git a/.github/strategy/adapters.json b/.github/strategy/adapters.json index 7595cedf2a..ae53f2478d 100644 --- a/.github/strategy/adapters.json +++ b/.github/strategy/adapters.json @@ -38,6 +38,7 @@ "deribit", "dns-query", "dxfeed", + "dxfeed-secondary", "eodhistoricaldata", "etherchain", "ethgasstation", diff --git a/dxfeed-secondary/.eslintrc.js b/dxfeed-secondary/.eslintrc.js new file mode 100644 index 0000000000..11f16f9a15 --- /dev/null +++ b/dxfeed-secondary/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('../.eslintrc.ts.js'), +} diff --git a/dxfeed-secondary/README.md b/dxfeed-secondary/README.md new file mode 100644 index 0000000000..ab2487d8fb --- /dev/null +++ b/dxfeed-secondary/README.md @@ -0,0 +1,44 @@ +# Chainlink External Adapter for dxFeed + +## Configuration + +This adapter supports the following environment variables: + +- `API_USERNAME`: Your API username +- `API_PASSWORD`: Your API password +- `API_ENDPOINT`: The endpoint for your dxFeed. Defaults to the demo endpoint (`https://tools.dxfeed.com/webservice/rest`) + +## Input Params + +- `base`, `from`, or `asset`: The symbol of the asset to query +- `endpoint`: Optional endpoint param + +## Output + +```json +{ + "jobRunID":"1", + "data":{ + "status":"OK", + "Trade":{ + "UKX:FTSE":{ + "eventSymbol":"UKX:FTSE", + "eventTime":0, + "time":1593001772000, + "timeNanoPart":0, + "sequence":115972, + "exchangeCode":"", + "price":6194.63, + "size":0, + "dayVolume":0, + "dayTurnover":"NaN", + "tickDirection":"ZERO_UP", + "extendedTradingHours":false + } + }, + "result":6194.63 + }, + "result":6194.63, + "statusCode":200 +} +``` diff --git a/dxfeed-secondary/package.json b/dxfeed-secondary/package.json new file mode 100644 index 0000000000..1c7f542776 --- /dev/null +++ b/dxfeed-secondary/package.json @@ -0,0 +1,47 @@ +{ + "name": "@chainlink/dxfeed-secondary-adapter", + "version": "0.0.1", + "description": "Chainlink dxfeed secondary adapter.", + "keywords": [ + "Chainlink", + "LINK", + "blockchain", + "oracle", + "dxfeed" + ], + "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": { + "prepublishOnly": "yarn build && yarn test:unit", + "setup": "yarn build", + "build": "tsc -b", + "lint": "eslint --ignore-path ../.eslintignore . --ext .js,.jsx,.ts,.tsx", + "lint:fix": "eslint --ignore-path ../.eslintignore . --ext .js,.jsx,.ts,.tsx --fix", + "test": "mocha --exit --timeout 3000 -r ts-node/register 'test/**/*.test.ts'", + "test:unit": "mocha --exit --grep @integration --invert -r ts-node/register 'test/**/*.test.ts'", + "test:integration": "mocha --exit --timeout 3000 --grep @integration -r ts-node/register 'test/**/*.test.ts'", + "server:dist": "node -e 'require(\"./dist/index.js\").server()'", + "start": "yarn server:dist" + }, + "devDependencies": { + "@types/chai": "^4.2.11", + "@types/express": "^4.17.6", + "@types/mocha": "^7.0.2", + "@types/node": "^14.0.13", + "@typescript-eslint/eslint-plugin": "^3.9.0", + "@typescript-eslint/parser": "^3.9.0", + "ts-node": "^8.10.2", + "typescript": "^3.9.7" + }, + "dependencies": { + "@chainlink/dxfeed-adapter": "0.0.1" + } +} diff --git a/dxfeed-secondary/src/adapter.ts b/dxfeed-secondary/src/adapter.ts new file mode 100644 index 0000000000..f237a15b60 --- /dev/null +++ b/dxfeed-secondary/src/adapter.ts @@ -0,0 +1,36 @@ +import { Requester, Validator, AdapterError } from '@chainlink/external-adapter' +import { ExecuteWithConfig, ExecuteFactory, Config } from '@chainlink/types' +import { makeConfig, DEFAULT_ENDPOINT } from './config' +import { price } from './endpoint' + +const inputParams = { + endpoint: false, +} + +export const execute: ExecuteWithConfig = async (request, config) => { + const validator = new Validator(request, inputParams) + if (validator.error) throw validator.error + + Requester.logConfig(config) + + const jobRunID = validator.validated.id + const endpoint = validator.validated.data.endpoint || DEFAULT_ENDPOINT + + switch (endpoint) { + case price.NAME: { + return await price.execute(request, config) + break + } + default: { + throw new AdapterError({ + jobRunID, + message: `Endpoint ${endpoint} not supported.`, + statusCode: 400, + }) + } + } +} + +export const makeExecute: ExecuteFactory = (config) => { + return async (request) => execute(request, config || makeConfig()) +} diff --git a/dxfeed-secondary/src/config.ts b/dxfeed-secondary/src/config.ts new file mode 100644 index 0000000000..2fad783a96 --- /dev/null +++ b/dxfeed-secondary/src/config.ts @@ -0,0 +1,6 @@ +import { Requester } from '@chainlink/external-adapter' +import { Config } from '@chainlink/types' + +export const DEFAULT_ENDPOINT = 'price' + +export const makeConfig = (prefix?: string): Config => Requester.getDefaultConfig(prefix) diff --git a/dxfeed-secondary/src/endpoint/index.ts b/dxfeed-secondary/src/endpoint/index.ts new file mode 100644 index 0000000000..7fca076fed --- /dev/null +++ b/dxfeed-secondary/src/endpoint/index.ts @@ -0,0 +1 @@ +export * as price from './price' diff --git a/dxfeed-secondary/src/endpoint/price.ts b/dxfeed-secondary/src/endpoint/price.ts new file mode 100644 index 0000000000..1f83b36847 --- /dev/null +++ b/dxfeed-secondary/src/endpoint/price.ts @@ -0,0 +1,30 @@ +import { Validator } from '@chainlink/external-adapter' +import { ExecuteWithConfig, Config } from '@chainlink/types' +import * as dxfeed from '@chainlink/dxfeed-adapter' + +export const NAME = 'price' + +const customParams = { + base: ['base', 'from', 'coin'], +} + +const commonSymbols: { [key: string]: string } = { + N225: 'NKY.IND:TEI', + FTSE: 'UKX.IND:TEI', + TSLA: 'TSLA.US:TEI', + TSLAX: 'TSLA:BFX', +} + +export const execute: ExecuteWithConfig = async (request, config) => { + const validator = new Validator(request, customParams) + if (validator.error) throw validator.error + + let symbol = validator.validated.data.base.toUpperCase() + if (symbol in commonSymbols) { + symbol = commonSymbols[symbol] + } + request.data.base = symbol + + const exec = dxfeed.makeExecute(config) + return exec(request) +} diff --git a/dxfeed-secondary/src/index.ts b/dxfeed-secondary/src/index.ts new file mode 100644 index 0000000000..29fea729f7 --- /dev/null +++ b/dxfeed-secondary/src/index.ts @@ -0,0 +1,7 @@ +import { expose, util } from '@chainlink/ea-bootstrap' +import { makeExecute } from './adapter' +import { makeConfig } from './config' + +const NAME = 'DXFEED_SECONDARY' + +export = { NAME, makeExecute, makeConfig, ...expose(util.wrapExecute(makeExecute())) } diff --git a/dxfeed-secondary/test/adapter.test.ts b/dxfeed-secondary/test/adapter.test.ts new file mode 100644 index 0000000000..91e4f8c6e7 --- /dev/null +++ b/dxfeed-secondary/test/adapter.test.ts @@ -0,0 +1,66 @@ +import { assert } from 'chai' +import { Requester } from '@chainlink/external-adapter' +import { assertSuccess, assertError } from '@chainlink/adapter-test-helpers' +import { AdapterRequest } from '@chainlink/types' +import { makeExecute } from '../src/adapter' + +describe('execute', () => { + const jobID = '1' + const execute = makeExecute() + + context('successful calls @integration', () => { + const requests = [ + { name: 'id not supplied', testData: { data: { base: 'FTSE' } } }, + { name: 'base', testData: { id: jobID, data: { base: 'FTSE' } } }, + { name: 'from', testData: { id: jobID, data: { from: 'FTSE' } } }, + ] + + requests.forEach((req) => { + it(`${req.name}`, async () => { + const data = await execute(req.testData as AdapterRequest) + assertSuccess({ expected: 200, actual: data.statusCode }, data, jobID) + assert.isAbove(data.result, 0) + assert.isAbove(data.data.result, 0) + }) + }) + }) + + context('validation error', () => { + const requests = [ + { name: 'empty body', testData: {} }, + { name: 'empty data', testData: { data: {} } }, + { name: 'base not supplied', testData: { id: jobID, data: {} } }, + ] + + requests.forEach((req) => { + it(`${req.name}`, async () => { + try { + await execute(req.testData as AdapterRequest) + } catch (error) { + const errorResp = Requester.errored(jobID, error) + assertError({ expected: 400, actual: errorResp.statusCode }, errorResp, jobID) + } + }) + }) + }) + + context('error calls @integration', () => { + const requests = [ + { + name: 'unknown base', + testData: { id: jobID, data: { base: 'not_real' } }, + }, + ] + + requests.forEach((req) => { + it(`${req.name}`, async () => { + try { + await execute(req.testData as AdapterRequest) + } catch (error) { + const errorResp = Requester.errored(jobID, error) + assertError({ expected: 500, actual: errorResp.statusCode }, errorResp, jobID) + } + }) + }) + }) +}) diff --git a/dxfeed-secondary/tsconfig.json b/dxfeed-secondary/tsconfig.json new file mode 100644 index 0000000000..3b4ccf41fa --- /dev/null +++ b/dxfeed-secondary/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "typeRoots": ["../node_modules/@types", "../typings", "./typings"] + }, + "include": ["src/**/*"], + "exclude": ["dist", "**/*.spec.ts", "**/*.test.ts"] +} diff --git a/dxfeed/.eslintrc.js b/dxfeed/.eslintrc.js index 7d045a59de..11f16f9a15 100644 --- a/dxfeed/.eslintrc.js +++ b/dxfeed/.eslintrc.js @@ -1 +1,3 @@ -module.exports = require('../.eslintrc.js') +module.exports = { + ...require('../.eslintrc.ts.js'), +} diff --git a/dxfeed/adapter.js b/dxfeed/adapter.js deleted file mode 100644 index 8e1f1de824..0000000000 --- a/dxfeed/adapter.js +++ /dev/null @@ -1,59 +0,0 @@ -const { Requester, Validator } = require('@chainlink/external-adapter') -const username = process.env.API_USERNAME -const password = process.env.API_PASSWORD -const DEFAULT_DATA_ENDPOINT = 'events.json' -const DEMO_ENDPOINT = 'https://tools.dxfeed.com/webservice/rest' -const apiEndpoint = process.env.API_ENDPOINT || DEMO_ENDPOINT -if (apiEndpoint === DEMO_ENDPOINT) - console.warn(`Using demo endpoint: ${DEMO_ENDPOINT} (Please do not use in production!)`) - -const customError = (data) => data.status !== 'OK' - -const customParams = { - base: ['base', 'from', 'asset'], - endpoint: false, -} - -const commonSymbols = { - N225: 'NKY.IND:TEI', - FTSE: 'UKX.IND:TEI', - TSLA: 'TSLA:BFX', - TSLAX: 'TSLA.US:TEI', -} - -const execute = (input, callback) => { - const validator = new Validator(input, customParams) - if (validator.error) return callback(validator.error.statusCode, validator.errored) - - const jobRunID = validator.validated.id - const endpoint = validator.validated.data.endpoint || DEFAULT_DATA_ENDPOINT - const url = `${apiEndpoint}/${endpoint}` - let symbols = validator.validated.data.base.toUpperCase() - if (symbols in commonSymbols) { - symbols = commonSymbols[symbols] - } - - const params = { - events: 'Trade', - symbols, - } - - const config = { - url, - params, - auth: { username, password }, - } - - Requester.request(config, customError) - .then((response) => { - response.data.result = Requester.validateResultNumber(response.data, [ - 'Trade', - symbols, - 'price', - ]) - callback(response.status, Requester.success(jobRunID, response)) - }) - .catch((error) => callback(500, Requester.errored(jobRunID, error))) -} - -module.exports.execute = execute diff --git a/dxfeed/index.js b/dxfeed/index.js deleted file mode 100644 index d5dfd92b9f..0000000000 --- a/dxfeed/index.js +++ /dev/null @@ -1,4 +0,0 @@ -const { expose } = require('@chainlink/ea-bootstrap') -const { execute } = require('./adapter') - -module.exports = expose(execute) diff --git a/dxfeed/package.json b/dxfeed/package.json index 83acd8f0bf..7fb3791c60 100644 --- a/dxfeed/package.json +++ b/dxfeed/package.json @@ -1,15 +1,45 @@ { "name": "@chainlink/dxfeed-adapter", "version": "0.0.1", + "description": "Chainlink dxfeed adapter.", + "keywords": [ + "Chainlink", + "LINK", + "blockchain", + "oracle", + "dxfeed" + ], + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "repository": { + "url": "https://github.com/smartcontractkit/external-adapters-js", + "type": "git" + }, "license": "MIT", - "main": "index.js", "scripts": { - "server": "node -e 'require(\"./index.js\").server()'", + "prepublishOnly": "yarn build && yarn test:unit", + "setup": "yarn build", + "build": "tsc -b", "lint": "eslint --ignore-path ../.eslintignore . --ext .js,.jsx,.ts,.tsx", "lint:fix": "eslint --ignore-path ../.eslintignore . --ext .js,.jsx,.ts,.tsx --fix", - "test": "yarn _mocha --timeout 0", - "test:unit": "yarn _mocha --grep @integration --invert --timeout 0", - "test:integration": "yarn _mocha --grep @integration --timeout 0" + "test": "mocha --exit --timeout 3000 -r ts-node/register 'test/**/*.test.ts'", + "test:unit": "mocha --exit --grep @integration --invert -r ts-node/register 'test/**/*.test.ts'", + "test:integration": "mocha --exit --timeout 3000 --grep @integration -r ts-node/register 'test/**/*.test.ts'", + "server:dist": "node -e 'require(\"./dist/index.js\").server()'", + "start": "yarn server:dist" + }, + "devDependencies": { + "@types/chai": "^4.2.11", + "@types/express": "^4.17.6", + "@types/mocha": "^7.0.2", + "@types/node": "^14.0.13", + "@typescript-eslint/eslint-plugin": "^3.9.0", + "@typescript-eslint/parser": "^3.9.0", + "ts-node": "^8.10.2", + "typescript": "^3.9.7" }, "dependencies": {} } diff --git a/dxfeed/src/adapter.ts b/dxfeed/src/adapter.ts new file mode 100644 index 0000000000..f237a15b60 --- /dev/null +++ b/dxfeed/src/adapter.ts @@ -0,0 +1,36 @@ +import { Requester, Validator, AdapterError } from '@chainlink/external-adapter' +import { ExecuteWithConfig, ExecuteFactory, Config } from '@chainlink/types' +import { makeConfig, DEFAULT_ENDPOINT } from './config' +import { price } from './endpoint' + +const inputParams = { + endpoint: false, +} + +export const execute: ExecuteWithConfig = async (request, config) => { + const validator = new Validator(request, inputParams) + if (validator.error) throw validator.error + + Requester.logConfig(config) + + const jobRunID = validator.validated.id + const endpoint = validator.validated.data.endpoint || DEFAULT_ENDPOINT + + switch (endpoint) { + case price.NAME: { + return await price.execute(request, config) + break + } + default: { + throw new AdapterError({ + jobRunID, + message: `Endpoint ${endpoint} not supported.`, + statusCode: 400, + }) + } + } +} + +export const makeExecute: ExecuteFactory = (config) => { + return async (request) => execute(request, config || makeConfig()) +} diff --git a/dxfeed/src/config.ts b/dxfeed/src/config.ts new file mode 100644 index 0000000000..2fad783a96 --- /dev/null +++ b/dxfeed/src/config.ts @@ -0,0 +1,6 @@ +import { Requester } from '@chainlink/external-adapter' +import { Config } from '@chainlink/types' + +export const DEFAULT_ENDPOINT = 'price' + +export const makeConfig = (prefix?: string): Config => Requester.getDefaultConfig(prefix) diff --git a/dxfeed/src/endpoint/index.ts b/dxfeed/src/endpoint/index.ts new file mode 100644 index 0000000000..7fca076fed --- /dev/null +++ b/dxfeed/src/endpoint/index.ts @@ -0,0 +1 @@ +export * as price from './price' diff --git a/dxfeed/src/endpoint/price.ts b/dxfeed/src/endpoint/price.ts new file mode 100644 index 0000000000..2bc779b994 --- /dev/null +++ b/dxfeed/src/endpoint/price.ts @@ -0,0 +1,61 @@ +import { Requester, Validator } from '@chainlink/external-adapter' +import { ExecuteWithConfig, Config } from '@chainlink/types' + +const DEMO_ENDPOINT = 'https://tools.dxfeed.com/webservice/rest' +const DEFAULT_DATA_ENDPOINT = 'events.json' + +export const NAME = 'price' + +const customError = (data: any) => data.Response === 'Error' + +const customParams = { + base: ['base', 'from', 'coin'], +} + +const commonSymbols: { [key: string]: string } = { + N225: 'NKY.IND:TEI', + FTSE: 'UKX.IND:TEI', + TSLA: 'TSLA:BFX', + TSLAX: 'TSLA.US:TEI', +} + +export const execute: ExecuteWithConfig = async (request, config) => { + const validator = new Validator(request, customParams) + if (validator.error) throw validator.error + + const username = process.env.API_USERNAME + const password = process.env.API_PASSWORD + + const apiEndpoint = process.env.API_ENDPOINT || DEMO_ENDPOINT + if (apiEndpoint === DEMO_ENDPOINT) + console.warn(`Using demo endpoint: ${DEMO_ENDPOINT} (Please do not use in production!)`) + + const jobRunID = validator.validated.id + const endpoint = validator.validated.data.endpoint || DEFAULT_DATA_ENDPOINT + const url = `${apiEndpoint}/${endpoint}` + let symbols = validator.validated.data.base.toUpperCase() + if (symbols in commonSymbols) { + symbols = commonSymbols[symbols] + } + + const params = { + events: 'Trade', + symbols, + } + + const options = { + ...config.api, + url, + params, + auth: { username, password }, + } + + const response = await Requester.request(options, customError) + const result = Requester.validateResultNumber(response.data, ['Trade', symbols, 'price']) + + return Requester.success(jobRunID, { + data: { result }, + result, + status: 200, + }) +} diff --git a/dxfeed/src/index.ts b/dxfeed/src/index.ts new file mode 100644 index 0000000000..4c4aa978ad --- /dev/null +++ b/dxfeed/src/index.ts @@ -0,0 +1,7 @@ +import { expose, util } from '@chainlink/ea-bootstrap' +import { makeExecute } from './adapter' +import { makeConfig } from './config' + +const NAME = 'DXFEED' + +export = { NAME, makeExecute, makeConfig, ...expose(util.wrapExecute(makeExecute())) } diff --git a/dxfeed/test/adapter.test.ts b/dxfeed/test/adapter.test.ts new file mode 100644 index 0000000000..91e4f8c6e7 --- /dev/null +++ b/dxfeed/test/adapter.test.ts @@ -0,0 +1,66 @@ +import { assert } from 'chai' +import { Requester } from '@chainlink/external-adapter' +import { assertSuccess, assertError } from '@chainlink/adapter-test-helpers' +import { AdapterRequest } from '@chainlink/types' +import { makeExecute } from '../src/adapter' + +describe('execute', () => { + const jobID = '1' + const execute = makeExecute() + + context('successful calls @integration', () => { + const requests = [ + { name: 'id not supplied', testData: { data: { base: 'FTSE' } } }, + { name: 'base', testData: { id: jobID, data: { base: 'FTSE' } } }, + { name: 'from', testData: { id: jobID, data: { from: 'FTSE' } } }, + ] + + requests.forEach((req) => { + it(`${req.name}`, async () => { + const data = await execute(req.testData as AdapterRequest) + assertSuccess({ expected: 200, actual: data.statusCode }, data, jobID) + assert.isAbove(data.result, 0) + assert.isAbove(data.data.result, 0) + }) + }) + }) + + context('validation error', () => { + const requests = [ + { name: 'empty body', testData: {} }, + { name: 'empty data', testData: { data: {} } }, + { name: 'base not supplied', testData: { id: jobID, data: {} } }, + ] + + requests.forEach((req) => { + it(`${req.name}`, async () => { + try { + await execute(req.testData as AdapterRequest) + } catch (error) { + const errorResp = Requester.errored(jobID, error) + assertError({ expected: 400, actual: errorResp.statusCode }, errorResp, jobID) + } + }) + }) + }) + + context('error calls @integration', () => { + const requests = [ + { + name: 'unknown base', + testData: { id: jobID, data: { base: 'not_real' } }, + }, + ] + + requests.forEach((req) => { + it(`${req.name}`, async () => { + try { + await execute(req.testData as AdapterRequest) + } catch (error) { + const errorResp = Requester.errored(jobID, error) + assertError({ expected: 500, actual: errorResp.statusCode }, errorResp, jobID) + } + }) + }) + }) +}) diff --git a/dxfeed/test/adapter_test.js b/dxfeed/test/adapter_test.js deleted file mode 100644 index 317ede5eb4..0000000000 --- a/dxfeed/test/adapter_test.js +++ /dev/null @@ -1,62 +0,0 @@ -const { assert } = require('chai') -const { assertSuccess, assertError } = require('@chainlink/adapter-test-helpers') -const { execute } = require('../adapter') - -describe('execute', () => { - const jobID = '1' - - context('successful calls @integration', () => { - const requests = [ - { name: 'id not supplied', testData: { data: { base: 'FTSE' } } }, - { name: 'base', testData: { id: jobID, data: { base: 'FTSE' } } }, - { name: 'from', testData: { id: jobID, data: { from: 'FTSE' } } }, - ] - - requests.forEach((req) => { - it(`${req.name}`, (done) => { - execute(req.testData, (statusCode, data) => { - assertSuccess({ expected: 200, actual: statusCode }, data, jobID) - assert.isAbove(data.result, 0) - assert.isAbove(data.data.result, 0) - assert.equal(data.result, data.data.result) - done() - }) - }) - }) - }) - - context('validation error', () => { - const requests = [ - { name: 'empty body', testData: {} }, - { name: 'empty data', testData: { data: {} } }, - { name: 'base not supplied', testData: { id: jobID, data: {} } }, - ] - - requests.forEach((req) => { - it(`${req.name}`, (done) => { - execute(req.testData, (statusCode, data) => { - assertError({ expected: 400, actual: statusCode }, data, jobID) - done() - }) - }) - }) - }) - - context('error calls @integration', () => { - const requests = [ - { - name: 'unknown base', - testData: { id: jobID, data: { base: 'not_real' } }, - }, - ] - - requests.forEach((req) => { - it(`${req.name}`, (done) => { - execute(req.testData, (statusCode, data) => { - assertError({ expected: 500, actual: statusCode }, data, jobID) - done() - }) - }) - }) - }) -}) diff --git a/dxfeed/tsconfig.json b/dxfeed/tsconfig.json new file mode 100644 index 0000000000..3b4ccf41fa --- /dev/null +++ b/dxfeed/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "typeRoots": ["../node_modules/@types", "../typings", "./typings"] + }, + "include": ["src/**/*"], + "exclude": ["dist", "**/*.spec.ts", "**/*.test.ts"] +} diff --git a/package.json b/package.json index e54b7f9443..1f0fccc12f 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "metalsapi", "bravenewcoin-vwap", "dxfeed", + "dxfeed-secondary", "tradingeconomics", "marketstack", "nikkei", From faef69632b57b4f82041f351538f574c4cd558b1 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 28 Jan 2021 13:55:39 -0600 Subject: [PATCH 2/4] Add to README, CHANGELOG, and bump dxfeed version for TS --- CHANGELOG.md | 1 + dxfeed-secondary/README.md | 50 ++++++++++++++++++--------------- dxfeed-secondary/package.json | 2 +- dxfeed/README.md | 53 ++++++++++++++++++++--------------- dxfeed/package.json | 2 +- 5 files changed, 62 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2eaa7222d..c727429652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - `bitcoin-json-rpc`: composite adapter for querying bitcoin blockchain stats(difficulty, height) according to the existing convention - `iex-cloud` to get stock and crypto market data from IEX Cloud - `cfbenchmarks` to get crypto benchmarks and indices + - `dxfeed-secondary` to handle secondary mappings for the TSLA symbol - Added support for metadata in requests. This gives adapters access to the FM on-chain round state. - Moves re-usable test behaviors & testing utils to a new package - `@chainlink/adapter-test-helpers` - Added support for using query string parameters as input to adapters. diff --git a/dxfeed-secondary/README.md b/dxfeed-secondary/README.md index ab2487d8fb..836614a488 100644 --- a/dxfeed-secondary/README.md +++ b/dxfeed-secondary/README.md @@ -1,5 +1,11 @@ # Chainlink External Adapter for dxFeed +An adapter to add secondary mapping for symbols: + +```bash +TSLA ➡️ 'TSLA.US:TEI' +``` + ## Configuration This adapter supports the following environment variables: @@ -17,28 +23,28 @@ This adapter supports the following environment variables: ```json { - "jobRunID":"1", - "data":{ - "status":"OK", - "Trade":{ - "UKX:FTSE":{ - "eventSymbol":"UKX:FTSE", - "eventTime":0, - "time":1593001772000, - "timeNanoPart":0, - "sequence":115972, - "exchangeCode":"", - "price":6194.63, - "size":0, - "dayVolume":0, - "dayTurnover":"NaN", - "tickDirection":"ZERO_UP", - "extendedTradingHours":false - } - }, - "result":6194.63 + "jobRunID": "1", + "data": { + "status": "OK", + "Trade": { + "UKX:FTSE": { + "eventSymbol": "UKX:FTSE", + "eventTime": 0, + "time": 1593001772000, + "timeNanoPart": 0, + "sequence": 115972, + "exchangeCode": "", + "price": 6194.63, + "size": 0, + "dayVolume": 0, + "dayTurnover": "NaN", + "tickDirection": "ZERO_UP", + "extendedTradingHours": false + } }, - "result":6194.63, - "statusCode":200 + "result": 6194.63 + }, + "result": 6194.63, + "statusCode": 200 } ``` diff --git a/dxfeed-secondary/package.json b/dxfeed-secondary/package.json index 1c7f542776..1f8ba3c84d 100644 --- a/dxfeed-secondary/package.json +++ b/dxfeed-secondary/package.json @@ -42,6 +42,6 @@ "typescript": "^3.9.7" }, "dependencies": { - "@chainlink/dxfeed-adapter": "0.0.1" + "@chainlink/dxfeed-adapter": "0.0.2" } } diff --git a/dxfeed/README.md b/dxfeed/README.md index ab2487d8fb..434cbb3c40 100644 --- a/dxfeed/README.md +++ b/dxfeed/README.md @@ -13,32 +13,41 @@ This adapter supports the following environment variables: - `base`, `from`, or `asset`: The symbol of the asset to query - `endpoint`: Optional endpoint param +The `base` param handles the following symbol conversions: + +```bash +N225 ➡️ 'NKY.IND:TEI' +FTSE ➡️ 'UKX.IND:TEI' +TSLA ➡️ 'TSLA:BFX' +TSLAX ➡️ 'TSLA.US:TEI' +``` + ## Output ```json { - "jobRunID":"1", - "data":{ - "status":"OK", - "Trade":{ - "UKX:FTSE":{ - "eventSymbol":"UKX:FTSE", - "eventTime":0, - "time":1593001772000, - "timeNanoPart":0, - "sequence":115972, - "exchangeCode":"", - "price":6194.63, - "size":0, - "dayVolume":0, - "dayTurnover":"NaN", - "tickDirection":"ZERO_UP", - "extendedTradingHours":false - } - }, - "result":6194.63 + "jobRunID": "1", + "data": { + "status": "OK", + "Trade": { + "UKX:FTSE": { + "eventSymbol": "UKX:FTSE", + "eventTime": 0, + "time": 1593001772000, + "timeNanoPart": 0, + "sequence": 115972, + "exchangeCode": "", + "price": 6194.63, + "size": 0, + "dayVolume": 0, + "dayTurnover": "NaN", + "tickDirection": "ZERO_UP", + "extendedTradingHours": false + } }, - "result":6194.63, - "statusCode":200 + "result": 6194.63 + }, + "result": 6194.63, + "statusCode": 200 } ``` diff --git a/dxfeed/package.json b/dxfeed/package.json index 7fb3791c60..93778b90c5 100644 --- a/dxfeed/package.json +++ b/dxfeed/package.json @@ -1,6 +1,6 @@ { "name": "@chainlink/dxfeed-adapter", - "version": "0.0.1", + "version": "0.0.2", "description": "Chainlink dxfeed adapter.", "keywords": [ "Chainlink", From 7125c154252bbd693c59fb194a2c49500f941d2d Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 28 Jan 2021 14:25:01 -0600 Subject: [PATCH 3/4] Re-add server script for docker --- dxfeed-secondary/package.json | 1 + dxfeed/package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/dxfeed-secondary/package.json b/dxfeed-secondary/package.json index 1f8ba3c84d..9351f7da4f 100644 --- a/dxfeed-secondary/package.json +++ b/dxfeed-secondary/package.json @@ -28,6 +28,7 @@ "test": "mocha --exit --timeout 3000 -r ts-node/register 'test/**/*.test.ts'", "test:unit": "mocha --exit --grep @integration --invert -r ts-node/register 'test/**/*.test.ts'", "test:integration": "mocha --exit --timeout 3000 --grep @integration -r ts-node/register 'test/**/*.test.ts'", + "server": "node -e 'require(\"./index.js\").server()'", "server:dist": "node -e 'require(\"./dist/index.js\").server()'", "start": "yarn server:dist" }, diff --git a/dxfeed/package.json b/dxfeed/package.json index 93778b90c5..c071da25f1 100644 --- a/dxfeed/package.json +++ b/dxfeed/package.json @@ -28,6 +28,7 @@ "test": "mocha --exit --timeout 3000 -r ts-node/register 'test/**/*.test.ts'", "test:unit": "mocha --exit --grep @integration --invert -r ts-node/register 'test/**/*.test.ts'", "test:integration": "mocha --exit --timeout 3000 --grep @integration -r ts-node/register 'test/**/*.test.ts'", + "server": "node -e 'require(\"./index.js\").server()'", "server:dist": "node -e 'require(\"./dist/index.js\").server()'", "start": "yarn server:dist" }, From dadf568c11b84c0192103b81630c805f2baee151 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 28 Jan 2021 14:32:55 -0600 Subject: [PATCH 4/4] Removes TSLAX symbol conversion --- dxfeed-secondary/src/endpoint/price.ts | 1 - dxfeed/src/endpoint/price.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/dxfeed-secondary/src/endpoint/price.ts b/dxfeed-secondary/src/endpoint/price.ts index 1f83b36847..ef514a13a6 100644 --- a/dxfeed-secondary/src/endpoint/price.ts +++ b/dxfeed-secondary/src/endpoint/price.ts @@ -12,7 +12,6 @@ const commonSymbols: { [key: string]: string } = { N225: 'NKY.IND:TEI', FTSE: 'UKX.IND:TEI', TSLA: 'TSLA.US:TEI', - TSLAX: 'TSLA:BFX', } export const execute: ExecuteWithConfig = async (request, config) => { diff --git a/dxfeed/src/endpoint/price.ts b/dxfeed/src/endpoint/price.ts index 2bc779b994..5f99a49e92 100644 --- a/dxfeed/src/endpoint/price.ts +++ b/dxfeed/src/endpoint/price.ts @@ -16,7 +16,6 @@ const commonSymbols: { [key: string]: string } = { N225: 'NKY.IND:TEI', FTSE: 'UKX.IND:TEI', TSLA: 'TSLA:BFX', - TSLAX: 'TSLA.US:TEI', } export const execute: ExecuteWithConfig = async (request, config) => {