Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Peregrine Data External Adapter Submission #3590

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
3 changes: 3 additions & 0 deletions packages/sources/peregrine-fund-admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Chainlink External Adapter for peregrine-fund-admin

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 peregrine-fund-admin`.
40 changes: 40 additions & 0 deletions packages/sources/peregrine-fund-admin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@chainlink/peregrine-fund-admin-adapter",
"version": "0.0.0",
"description": "Chainlink peregrine-fund-admin adapter.",
"keywords": [
"Chainlink",
"LINK",
"blockchain",
"oracle",
"peregrine-fund-admin"
],
"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.115",
"nock": "13.5.4",
"typescript": "5.5.4"
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
},
"dependencies": {
"@chainlink/external-adapter-framework": "1.7.1",
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
"tslib": "2.4.1"
}
}
15 changes: 15 additions & 0 deletions packages/sources/peregrine-fund-admin/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { AdapterConfig } from '@chainlink/external-adapter-framework/config'
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved

export const config = new AdapterConfig({
API_KEY: {
description: 'An API key for Data Provider',
type: 'string',
required: true,
sensitive: true,
},
API_ENDPOINT: {
description: 'An API endpoint for Data Provider',
type: 'string',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values seems to be lost?

default: 'https://fund-admin-data-adapter-v1-960005989691.europe-west2.run.app',
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
"peregrine-fund-admin": {}
}
2 changes: 2 additions & 0 deletions packages/sources/peregrine-fund-admin/src/endpoint/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { endpoint as nav } from './nav'
export { endpoint as reserve } from './reserve'
35 changes: 35 additions & 0 deletions packages/sources/peregrine-fund-admin/src/endpoint/nav.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 overrides from '../config/overrides.json'
import { httpTransport } from '../transport/nav'

// Input parameters define the structure of the request expected by the endpoint. The second parameter defines example input data that will be used in EA readme
export const inputParameters = new InputParameters({
assetId: {
aliases: ['assetId'],
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
required: true,
type: 'number',
description: 'The identifying number for the requested asset',
},
})
// Endpoints contain a type parameter that allows specifying relevant types of an endpoint, for example, request payload type, Adapter response type and Adapter configuration (environment variables) type
export type BaseEndpointTypes = {
Parameters: typeof inputParameters.definition
Response: SingleNumberResultResponse
Settings: typeof config.settings
}

export const endpoint = new AdapterEndpoint({
// Endpoint name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can get rid of the comments in this object

name: 'nav',
// Alternative endpoint names for this endpoint
aliases: [],
// Transport handles incoming requests, data processing and communication for this endpoint
transport: httpTransport,
// Supported input parameters for this endpoint
inputParameters,
// Overrides are defined in the `/config/overrides.json` file. They allow input parameters to be overriden from a generic symbol to something more specific for the data provider such as an ID.
overrides: overrides['peregrine-fund-admin'],
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
})
35 changes: 35 additions & 0 deletions packages/sources/peregrine-fund-admin/src/endpoint/reserve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 overrides from '../config/overrides.json'
import { httpTransport } from '../transport/reserve'

// Input parameters define the structure of the request expected by the endpoint. The second parameter defines example input data that will be used in EA readme
export const inputParameters = new InputParameters({
assetId: {
aliases: ['assetId'],
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
required: true,
type: 'number',
description: 'The identifying number for the requested asset',
},
})
// Endpoints contain a type parameter that allows specifying relevant types of an endpoint, for example, request payload type, Adapter response type and Adapter configuration (environment variables) type
export type BaseEndpointTypes = {
Parameters: typeof inputParameters.definition
Response: SingleNumberResultResponse
Settings: typeof config.settings
}

export const endpoint = new AdapterEndpoint({
// Endpoint name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too please

name: 'reserve',
// Alternative endpoint names for this endpoint
aliases: [],
// Transport handles incoming requests, data processing and communication for this endpoint
transport: httpTransport,
// Supported input parameters for this endpoint
inputParameters,
// Overrides are defined in the `/config/overrides.json` file. They allow input parameters to be overriden from a generic symbol to something more specific for the data provider such as an ID.
overrides: overrides['peregrine-fund-admin'],
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
})
17 changes: 17 additions & 0 deletions packages/sources/peregrine-fund-admin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
import { Adapter } from '@chainlink/external-adapter-framework/adapter'
import { config } from './config'
import { nav, reserve } from './endpoint'

export const adapter = new Adapter({
//Requests will direct to this endpoint if the `endpoint` input parameter is not specified.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

defaultEndpoint: nav.name,
// Adapter name
name: 'PEREGRINE_FUND-ADMIN',
// Adapter configuration (environment variables)
config,
// List of supported endpoints
endpoints: [nav, reserve],
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
})

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

export interface ResponseSchema {
Id: string | null
assetId: string
seniorNAV: string
Copy link
Contributor

@mmcallister-cll mmcallister-cll Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also I'm curious why this senior NAV is capitalized while junior and equity use Nav?

juniorNav: string
equityNav: string
totalLiability: string
totalAccounts: string
totalCollateral: string
collateral: number[]
accounts: number[]
updateTimestamp: string
id: string | null
}

// HttpTransport extends base types from endpoint and adds additional, Provider-specific types like 'RequestBody', which is the type of
// request body (not the request to adapter, but the request that adapter sends to Data Provider), and 'ResponseBody' which is
// the type of raw response from Data Provider
export type HttpTransportTypes = BaseEndpointTypes & {
Provider: {
RequestBody: never
ResponseBody: ResponseSchema
}
}
// HttpTransport is used to fetch and process data from a Provider using HTTP(S) protocol. It usually needs two methods
// `prepareRequests` and `parseResponse`
export const httpTransport = new HttpTransport<HttpTransportTypes>({
// `prepareRequests` method receives request payloads sent to associated endpoint alongside adapter config(environment variables)
// and should return 'request information' to the Data Provider. Use this method to construct one or many requests, and the framework
// will send them to Data Provider
prepareRequests: (params, config) => {
return params.map((param) => {
return {
// `params` are parameters associated to this single request and will also be available in the 'parseResponse' method.
params: [param],
// `request` contains any valid axios request configuration
request: {
baseURL: config.API_ENDPOINT,
url: '/api/v1/nav/',
headers: {
X_API_KEY: config.API_KEY,
},
params: {
symbol: param.base.toUpperCase(),
convert: param.quote.toUpperCase(),
},
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
},
}
})
},
// `parseResponse` takes the 'params' specified in the `prepareRequests` and the 'response' from Data Provider and should return
// an array of response objects to be stored in cache. Use this method to construct a list of response objects for every parameter in 'params'
// and the framework will save them in cache and return to user
parseResponse: (params, response) => {
// In case error was received, it's a good practice to return meaningful information to user
if (!response.data) {
return params.map((param) => {
return {
params: param,
response: {
errorMessage: `The data provider didn't return any value for ${param.base}/${param.quote}`,
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
statusCode: 502,
},
}
})
}

// For successful responses for each 'param' a new response object is created and returned as an array
return params.map((param) => {
const result = response.data.equityNav
// Response objects, whether successful or errors, contain two properties, 'params' and 'response'. 'response' is what will be
// stored in the cache and returned as adapter response and 'params' determines the identifier so that the next request with same 'params'
// will immediately return the response from the cache
return {
params: param,
response: {
result,
data: {
result,
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
},
},
}
})
},
})
81 changes: 81 additions & 0 deletions packages/sources/peregrine-fund-admin/src/transport/reserve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { HttpTransport } from '@chainlink/external-adapter-framework/transports'
import { BaseEndpointTypes } from '../endpoint/reserve'

export interface ResponseSchema {
assetId: number
totalValue: string
currencyBase: string
accountIds: number[]
updateDateTime: string
}

// HttpTransport extends base types from endpoint and adds additional, Provider-specific types like 'RequestBody', which is the type of
// request body (not the request to adapter, but the request that adapter sends to Data Provider), and 'ResponseBody' which is
// the type of raw response from Data Provider
export type HttpTransportTypes = BaseEndpointTypes & {
Provider: {
RequestBody: never
ResponseBody: ResponseSchema
}
}
// HttpTransport is used to fetch and process data from a Provider using HTTP(S) protocol. It usually needs two methods
// `prepareRequests` and `parseResponse`
export const httpTransport = new HttpTransport<HttpTransportTypes>({
// `prepareRequests` method receives request payloads sent to associated endpoint alongside adapter config(environment variables)
// and should return 'request information' to the Data Provider. Use this method to construct one or many requests, and the framework
// will send them to Data Provider
prepareRequests: (params, config) => {
return params.map((param) => {
return {
// `params` are parameters associated to this single request and will also be available in the 'parseResponse' method.
params: [param],
// `request` contains any valid axios request configuration
request: {
baseURL: config.API_ENDPOINT,
url: '/api/v1/reserves/',
headers: {
X_API_KEY: config.API_KEY,
},
params: {
symbol: param.base.toUpperCase(),
convert: param.quote.toUpperCase(),
},
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
},
}
})
},
// `parseResponse` takes the 'params' specified in the `prepareRequests` and the 'response' from Data Provider and should return
// an array of response objects to be stored in cache. Use this method to construct a list of response objects for every parameter in 'params'
// and the framework will save them in cache and return to user
parseResponse: (params, response) => {
// In case error was received, it's a good practice to return meaningful information to user
if (!response.data) {
return params.map((param) => {
return {
params: param,
response: {
errorMessage: `The data provider didn't return any value for ${param.base}/${param.quote}`,
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
statusCode: 502,
},
}
})
}

// For successful responses for each 'param' a new response object is created and returned as an array
return params.map((param) => {
const result = response.data[param.base.toUpperCase()].price
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
// Response objects, whether successful or errors, contain two properties, 'params' and 'response'. 'response' is what will be
// stored in the cache and returned as adapter response and 'params' determines the identifier so that the next request with same 'params'
// will immediately return the response from the cache
return {
params: param,
response: {
result,
data: {
result,
},
},
}
})
},
})
6 changes: 6 additions & 0 deletions packages/sources/peregrine-fund-admin/test-payload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
droconnel22 marked this conversation as resolved.
Show resolved Hide resolved
"requests": [{
"from": "BTC",
"to": "USD"
}]
}
Loading
Loading