diff --git a/.changeset/purple-cobras-double.md b/.changeset/purple-cobras-double.md new file mode 100644 index 0000000000..c5bb7ef557 --- /dev/null +++ b/.changeset/purple-cobras-double.md @@ -0,0 +1,5 @@ +--- +'@chainlink/backed-fi-adapter': major +--- + +Version 1.0.0 of Backed-Fi EA diff --git a/.pnp.cjs b/.pnp.cjs index 2b2ecb4034..22bc5752c6 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -250,6 +250,10 @@ const RAW_RUNTIME_STATE = "name": "@chainlink/avalanche-platform-adapter",\ "reference": "workspace:packages/sources/avalanche-platform"\ },\ + {\ + "name": "@chainlink/backed-fi-adapter",\ + "reference": "workspace:packages/sources/backed-fi"\ + },\ {\ "name": "@chainlink/bank-frick-adapter",\ "reference": "workspace:packages/sources/bank-frick"\ @@ -982,6 +986,7 @@ const RAW_RUNTIME_STATE = ["@chainlink/apy-finance-test-adapter", ["workspace:packages/composites/apy-finance-test"]],\ ["@chainlink/augur-adapter", ["workspace:packages/composites/augur"]],\ ["@chainlink/avalanche-platform-adapter", ["workspace:packages/sources/avalanche-platform"]],\ + ["@chainlink/backed-fi-adapter", ["workspace:packages/sources/backed-fi"]],\ ["@chainlink/bank-frick-adapter", ["workspace:packages/sources/bank-frick"]],\ ["@chainlink/bea-adapter", ["workspace:packages/sources/bea"]],\ ["@chainlink/binance-adapter", ["workspace:packages/sources/binance"]],\ @@ -5372,6 +5377,21 @@ const RAW_RUNTIME_STATE = "linkType": "SOFT"\ }]\ ]],\ + ["@chainlink/backed-fi-adapter", [\ + ["workspace:packages/sources/backed-fi", {\ + "packageLocation": "./packages/sources/backed-fi/",\ + "packageDependencies": [\ + ["@chainlink/backed-fi-adapter", "workspace:packages/sources/backed-fi"],\ + ["@chainlink/external-adapter-framework", "npm:2.6.0"],\ + ["@types/jest", "npm:29.5.14"],\ + ["@types/node", "npm:22.14.1"],\ + ["nock", "npm:13.5.6"],\ + ["tslib", "npm:2.4.1"],\ + ["typescript", "patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5"]\ + ],\ + "linkType": "SOFT"\ + }]\ + ]],\ ["@chainlink/bank-frick-adapter", [\ ["workspace:packages/sources/bank-frick", {\ "packageLocation": "./packages/sources/bank-frick/",\ diff --git a/packages/sources/backed-fi/CHANGELOG.md b/packages/sources/backed-fi/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/sources/backed-fi/README.md b/packages/sources/backed-fi/README.md new file mode 100644 index 0000000000..532cfcb3f1 --- /dev/null +++ b/packages/sources/backed-fi/README.md @@ -0,0 +1,54 @@ +# BACKED_FI + +![0.0.0](https://img.shields.io/github/package-json/v/smartcontractkit/external-adapters-js?filename=packages/sources/backed-fi/package.json) ![v3](https://img.shields.io/badge/framework%20version-v3-blueviolet) + +This document was generated automatically. Please see [README Generator](../../scripts#readme-generator) for more info. + +## Environment Variables + +| Required? | Name | Description | Type | Options | Default | +| :-------: | :----------: | :---------------------------: | :----: | :-----: | :----------------------------------: | +| | API_ENDPOINT | An API endpoint for Backed-Fi | string | | `https://api.backed.fi/api/v1/token` | + +--- + +## Data Provider Rate Limits + +There are no rate limits for this adapter. + +--- + +## Input Parameters + +| Required? | Name | Description | Type | Options | Default | +| :-------: | :------: | :-----------------: | :----: | :--------------------------------: | :----------: | +| | endpoint | The endpoint to use | string | [multiplier](#multiplier-endpoint) | `multiplier` | + +## Multiplier Endpoint + +`multiplier` is the only supported name for this endpoint. + +### Input Params + +| Required? | Name | Aliases | Description | Type | Options | Default | Depends On | Not Valid With | +| :-------: | :---------: | :-----: | :--------------------------------: | :----: | :-----: | :-----: | :--------: | :------------: | +| ✅ | tokenSymbol | | The symbol of token to query | string | | | | | +| ✅ | network | | The symbol of the network to query | string | | | | | + +### Example + +Request: + +```json +{ + "data": { + "endpoint": "multiplier", + "tokenSymbol": "AMZNx", + "network": "Solana" + } +} +``` + +--- + +MIT License diff --git a/packages/sources/backed-fi/package.json b/packages/sources/backed-fi/package.json new file mode 100644 index 0000000000..54f36da569 --- /dev/null +++ b/packages/sources/backed-fi/package.json @@ -0,0 +1,40 @@ +{ + "name": "@chainlink/backed-fi-adapter", + "version": "0.0.0", + "description": "Chainlink backed-fi adapter.", + "keywords": [ + "Chainlink", + "LINK", + "blockchain", + "oracle", + "backed-fi" + ], + "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": "29.5.14", + "@types/node": "22.14.1", + "nock": "13.5.6", + "typescript": "5.8.3" + }, + "dependencies": { + "@chainlink/external-adapter-framework": "2.6.0", + "tslib": "2.4.1" + } +} diff --git a/packages/sources/backed-fi/src/config/index.ts b/packages/sources/backed-fi/src/config/index.ts new file mode 100644 index 0000000000..a432865a1b --- /dev/null +++ b/packages/sources/backed-fi/src/config/index.ts @@ -0,0 +1,9 @@ +import { AdapterConfig } from '@chainlink/external-adapter-framework/config' + +export const config = new AdapterConfig({ + API_ENDPOINT: { + description: 'An API endpoint for Backed-Fi', + type: 'string', + default: 'https://api.backed.fi/api/v1/token', + }, +}) diff --git a/packages/sources/backed-fi/src/endpoint/index.ts b/packages/sources/backed-fi/src/endpoint/index.ts new file mode 100644 index 0000000000..bf6b4fe457 --- /dev/null +++ b/packages/sources/backed-fi/src/endpoint/index.ts @@ -0,0 +1 @@ +export { endpoint as multiplier } from './multiplier' diff --git a/packages/sources/backed-fi/src/endpoint/multiplier.ts b/packages/sources/backed-fi/src/endpoint/multiplier.ts new file mode 100644 index 0000000000..56b0fa131f --- /dev/null +++ b/packages/sources/backed-fi/src/endpoint/multiplier.ts @@ -0,0 +1,48 @@ +import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter' +import { InputParameters } from '@chainlink/external-adapter-framework/validation' +import { config } from '../config' +import { httpTransport } from '../transport/multiplier' + +export const inputParameters = new InputParameters( + { + tokenSymbol: { + required: true, + type: 'string', + description: 'The symbol of token to query', + }, + network: { + required: true, + type: 'string', + description: 'The symbol of the network to query', + }, + }, + [ + { + tokenSymbol: 'AMZNx', + network: 'Solana', + }, + ], +) + +export type GMCIResultResponse = { + Result: number + Data: { + currentMultiplier: number + newMultiplier: number + activationDateTime: number + reason: string | null + } +} + +export type BaseEndpointTypes = { + Parameters: typeof inputParameters.definition + Response: GMCIResultResponse + Settings: typeof config.settings +} + +export const endpoint = new AdapterEndpoint({ + name: 'multiplier', + aliases: [], + transport: httpTransport, + inputParameters, +}) diff --git a/packages/sources/backed-fi/src/index.ts b/packages/sources/backed-fi/src/index.ts new file mode 100644 index 0000000000..425ba0102a --- /dev/null +++ b/packages/sources/backed-fi/src/index.ts @@ -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 { multiplier } from './endpoint' + +export const adapter = new Adapter({ + defaultEndpoint: multiplier.name, + name: 'BACKED_FI', + config, + endpoints: [multiplier], + rateLimiting: { + tiers: { + default: { + rateLimit1m: 6, + note: 'Setting reasonable default limits', + }, + }, + }, +}) + +export const server = (): Promise => expose(adapter) diff --git a/packages/sources/backed-fi/src/transport/multiplier.ts b/packages/sources/backed-fi/src/transport/multiplier.ts new file mode 100644 index 0000000000..f11ff829bd --- /dev/null +++ b/packages/sources/backed-fi/src/transport/multiplier.ts @@ -0,0 +1,70 @@ +import { HttpTransport } from '@chainlink/external-adapter-framework/transports' +import { BaseEndpointTypes } from '../endpoint/multiplier' + +export interface ResponseSchema { + activationDateTime: number + currentMultiplier: number + newMultiplier: number + reason: string | null + error: string + message: string +} + +export type HttpTransportTypes = BaseEndpointTypes & { + Provider: { + RequestBody: never + ResponseBody: ResponseSchema + } +} +export const httpTransport = new HttpTransport({ + prepareRequests: (params, config) => { + return params.map((param) => { + return { + params: [param], + request: { + baseURL: config.API_ENDPOINT, + url: `${param.tokenSymbol}/multiplier`, + params: { + network: param.network, + }, + }, + } + }) + }, + parseResponse: (params, response) => { + if (!response.data) { + return params.map((param) => { + return { + params: param, + response: { + errorMessage: `The data provider didn't return any value for ${param.tokenSymbol} on network ${param.network}`, + statusCode: 502, + }, + } + }) + } + + if (response.data.error) { + return params.map((param) => { + return { + params: param, + response: { + errorMessage: response.data.message, + statusCode: 502, + }, + } + }) + } + + return params.map((param) => { + const result = response.data.currentMultiplier + return { + params: param, + response: { + result: result, + data: response.data, + }, + } + }) + }, +}) diff --git a/packages/sources/backed-fi/test-payload.json b/packages/sources/backed-fi/test-payload.json new file mode 100644 index 0000000000..d359d31c8c --- /dev/null +++ b/packages/sources/backed-fi/test-payload.json @@ -0,0 +1,6 @@ +{ + "requests": [{ + "tokenSymbol": "METAx", + "network": "Arbitrum" + }] +} diff --git a/packages/sources/backed-fi/test/integration/__snapshots__/adapter.test.ts.snap b/packages/sources/backed-fi/test/integration/__snapshots__/adapter.test.ts.snap new file mode 100644 index 0000000000..cfec43a3a3 --- /dev/null +++ b/packages/sources/backed-fi/test/integration/__snapshots__/adapter.test.ts.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`execute multiplier endpoint should return failure - invalid network 1`] = ` +{ + "errorMessage": "Cannot read properties of undefined (reading 'multiplier')", + "statusCode": 502, + "timestamps": { + "providerDataReceivedUnixMs": 978347471111, + "providerDataRequestedUnixMs": 978347471111, + }, +} +`; + +exports[`execute multiplier endpoint should return success 1`] = ` +{ + "data": { + "activationDateTime": 0, + "currentMultiplier": 1, + "newMultiplier": 0, + "reason": null, + }, + "result": 1, + "statusCode": 200, + "timestamps": { + "providerDataReceivedUnixMs": 978347471111, + "providerDataRequestedUnixMs": 978347471111, + }, +} +`; diff --git a/packages/sources/backed-fi/test/integration/adapter.test.ts b/packages/sources/backed-fi/test/integration/adapter.test.ts new file mode 100644 index 0000000000..9dca8f0613 --- /dev/null +++ b/packages/sources/backed-fi/test/integration/adapter.test.ts @@ -0,0 +1,59 @@ +import { + TestAdapter, + setEnvVariables, +} from '@chainlink/external-adapter-framework/util/testing-utils' +import * as nock from 'nock' +import { mockResponseFailure, 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)) + + 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, + }) + }) + + afterAll(async () => { + setEnvVariables(oldEnv) + await testAdapter.api.close() + nock.restore() + nock.cleanAll() + spy.mockRestore() + }) + + describe('multiplier endpoint', () => { + it('should return success', async () => { + const data = { + tokenSymbol: 'METAx', + network: 'Arbitrum', + endpoint: 'multiplier', + } + mockResponseSuccess() + const response = await testAdapter.request(data) + expect(response.statusCode).toBe(200) + expect(response.json()).toMatchSnapshot() + }) + + it('should return failure - invalid network', async () => { + const data = { + tokenSymbol: 'METAx', + network: 'Ethereum', + endpoint: 'multiplier', + } + mockResponseFailure() + const response = await testAdapter.request(data) + expect(response.statusCode).toBe(502) + expect(response.json()).toMatchSnapshot() + }) + }) +}) diff --git a/packages/sources/backed-fi/test/integration/fixtures.ts b/packages/sources/backed-fi/test/integration/fixtures.ts new file mode 100644 index 0000000000..726a53bab1 --- /dev/null +++ b/packages/sources/backed-fi/test/integration/fixtures.ts @@ -0,0 +1,53 @@ +import nock from 'nock' + +export const mockResponseSuccess = (): nock.Scope => + nock('https://api.backed.fi/api/v1/token', { + encodedQueryParams: true, + }) + .get('/METAx/multiplier') + .query({ network: 'Arbitrum' }) + .reply( + 200, + () => ({ + activationDateTime: 0, + currentMultiplier: 1, + newMultiplier: 0, + reason: null, + }), + [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ], + ) + .persist() + +export const mockResponseFailure = (): nock.Scope => + nock('https://api.backed.fi/api/v1/token', { + encodedQueryParams: true, + }) + .get('/METAx/multiplier') + .query({ network: 'Ethereum' }) + .reply( + 200, + () => ({ + error: 'Something went wrong', + message: "Cannot read properties of undefined (reading 'multiplier')", + }), + [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ], + ) + .persist() diff --git a/packages/sources/backed-fi/tsconfig.json b/packages/sources/backed-fi/tsconfig.json new file mode 100644 index 0000000000..f59363fd76 --- /dev/null +++ b/packages/sources/backed-fi/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*", "src/**/*.json"], + "exclude": ["dist", "**/*.spec.ts", "**/*.test.ts"] +} diff --git a/packages/sources/backed-fi/tsconfig.test.json b/packages/sources/backed-fi/tsconfig.test.json new file mode 100755 index 0000000000..e3de28cb5c --- /dev/null +++ b/packages/sources/backed-fi/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*", "**/test", "src/**/*.json"], + "compilerOptions": { + "noEmit": true + } +} diff --git a/packages/tsconfig.json b/packages/tsconfig.json index fe2f777f19..d7187ebd5f 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -167,6 +167,9 @@ { "path": "./sources/avalanche-platform" }, + { + "path": "./sources/backed-fi" + }, { "path": "./sources/bank-frick" }, diff --git a/packages/tsconfig.test.json b/packages/tsconfig.test.json index 120334750f..ea592c2aef 100644 --- a/packages/tsconfig.test.json +++ b/packages/tsconfig.test.json @@ -167,6 +167,9 @@ { "path": "./sources/avalanche-platform/tsconfig.test.json" }, + { + "path": "./sources/backed-fi/tsconfig.test.json" + }, { "path": "./sources/bank-frick/tsconfig.test.json" }, diff --git a/yarn.lock b/yarn.lock index 94b15ca736..2b9231ff64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2621,6 +2621,19 @@ __metadata: languageName: unknown linkType: soft +"@chainlink/backed-fi-adapter@workspace:packages/sources/backed-fi": + version: 0.0.0-use.local + resolution: "@chainlink/backed-fi-adapter@workspace:packages/sources/backed-fi" + dependencies: + "@chainlink/external-adapter-framework": "npm:2.6.0" + "@types/jest": "npm:29.5.14" + "@types/node": "npm:22.14.1" + nock: "npm:13.5.6" + tslib: "npm:2.4.1" + typescript: "npm:5.8.3" + languageName: unknown + linkType: soft + "@chainlink/bank-frick-adapter@workspace:packages/sources/bank-frick": version: 0.0.0-use.local resolution: "@chainlink/bank-frick-adapter@workspace:packages/sources/bank-frick"