Skip to content

Commit afc403e

Browse files
Adds WisdomTree NAV EA (#3914)
* Adds wisdomtree EA * Adds changeset * Modify rate limit threshold * Adds HTTP header for auth * Typo * Adding trailing slash to avoid the 301 redirect * Adds wisdomtree ea to tsconfig * Fixes mocking * adding providerIndicatedTimeUnixMs --------- Co-authored-by: Matthew McAllister <matthew.mcallister@smartcontract.com>
1 parent 64486d3 commit afc403e

File tree

19 files changed

+350
-0
lines changed

19 files changed

+350
-0
lines changed

.changeset/curvy-olives-destroy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@chainlink/wisdomtree-adapter': major
3+
---
4+
5+
Adds Wisdomtree adapter

.pnp.cjs

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/sources/wisdomtree/CHANGELOG.md

Whitespace-only changes.

packages/sources/wisdomtree/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Chainlink External Adapter for wisdomtree
2+
3+
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 wisdomtree`.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "@chainlink/wisdomtree-adapter",
3+
"version": "0.0.0",
4+
"description": "Chainlink wisdomtree adapter.",
5+
"keywords": [
6+
"Chainlink",
7+
"LINK",
8+
"blockchain",
9+
"oracle",
10+
"wisdomtree"
11+
],
12+
"main": "dist/index.js",
13+
"types": "dist/index.d.ts",
14+
"files": [
15+
"dist"
16+
],
17+
"repository": {
18+
"url": "https://github.com/smartcontractkit/external-adapters-js",
19+
"type": "git"
20+
},
21+
"license": "MIT",
22+
"scripts": {
23+
"clean": "rm -rf dist && rm -f tsconfig.tsbuildinfo",
24+
"prepack": "yarn build",
25+
"build": "tsc -b",
26+
"server": "node -e 'require(\"./index.js\").server()'",
27+
"server:dist": "node -e 'require(\"./dist/index.js\").server()'",
28+
"start": "yarn server:dist"
29+
},
30+
"devDependencies": {
31+
"@types/jest": "^29.5.14",
32+
"@types/node": "22.14.1",
33+
"nock": "13.5.6",
34+
"typescript": "5.8.3"
35+
},
36+
"dependencies": {
37+
"@chainlink/external-adapter-framework": "2.6.0",
38+
"tslib": "2.4.1"
39+
}
40+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { AdapterConfig } from '@chainlink/external-adapter-framework/config'
2+
3+
export const config = new AdapterConfig({
4+
API_ENDPOINT: {
5+
description: 'An API endpoint for Data Provider',
6+
type: 'string',
7+
default: 'https://dataspanapi.wisdomtree.com',
8+
},
9+
API_KEY: {
10+
description: 'WisdomTree API key value',
11+
type: 'string',
12+
required: true,
13+
sensitive: true,
14+
},
15+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { endpoint as nav } from './nav'
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
2+
import { SingleNumberResultResponse } from '@chainlink/external-adapter-framework/util'
3+
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
4+
import { config } from '../config'
5+
import { httpTransport } from '../transport/nav'
6+
7+
export const inputParameters = new InputParameters(
8+
{
9+
ticker: {
10+
aliases: ['symbol', 'fundId'],
11+
required: true,
12+
type: 'string',
13+
description: 'The symbol of the fund ticker to query',
14+
},
15+
},
16+
[
17+
{
18+
ticker: 'WTGXX',
19+
},
20+
],
21+
)
22+
export type BaseEndpointTypes = {
23+
Parameters: typeof inputParameters.definition
24+
Response: SingleNumberResultResponse
25+
Settings: typeof config.settings
26+
}
27+
28+
export const endpoint = new AdapterEndpoint({
29+
name: 'nav',
30+
transport: httpTransport,
31+
inputParameters,
32+
})
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
2+
import { Adapter } from '@chainlink/external-adapter-framework/adapter'
3+
import { config } from './config'
4+
import { nav } from './endpoint'
5+
6+
export const adapter = new Adapter({
7+
defaultEndpoint: nav.name,
8+
name: 'WISDOMTREE',
9+
config,
10+
endpoints: [nav],
11+
rateLimiting: {
12+
tiers: {
13+
default: {
14+
rateLimit1m: 2,
15+
note: 'Reasonable limits',
16+
},
17+
},
18+
},
19+
})
20+
21+
export const server = (): Promise<ServerInstance | undefined> => expose(adapter)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { HttpTransport } from '@chainlink/external-adapter-framework/transports'
2+
import { BaseEndpointTypes } from '../endpoint/nav'
3+
4+
export interface ResponseSchema {
5+
ticker: string
6+
relatedTicker: string
7+
name: string
8+
dt: string
9+
nav: number
10+
sharesOutstanding: number
11+
aum: number
12+
navPrevious: number
13+
navDelta: number
14+
navDeltaPCT: number
15+
}
16+
17+
export type HttpTransportTypes = BaseEndpointTypes & {
18+
Provider: {
19+
RequestBody: never
20+
ResponseBody: ResponseSchema
21+
}
22+
}
23+
export const httpTransport = new HttpTransport<HttpTransportTypes>({
24+
prepareRequests: (params, config) => {
25+
return params.map((param) => {
26+
return {
27+
params: [param],
28+
request: {
29+
baseURL: config.API_ENDPOINT,
30+
url: '/funddetails/nav/',
31+
headers: {
32+
'x-wt-dataspan-key': config.API_KEY,
33+
},
34+
params: {
35+
ticker: param.ticker.toUpperCase(),
36+
},
37+
},
38+
}
39+
})
40+
},
41+
parseResponse: (params, response) => {
42+
if (!response.data) {
43+
return params.map((param) => {
44+
return {
45+
params: param,
46+
response: {
47+
errorMessage: `The data provider didn't return any value for ${param.ticker}`,
48+
statusCode: 502,
49+
},
50+
}
51+
})
52+
}
53+
54+
const timestamps = {
55+
providerIndicatedTimeUnixMs: new Date(response.data.dt).getTime(),
56+
}
57+
58+
return params.map((param) => {
59+
const result = response.data.nav
60+
return {
61+
params: param,
62+
response: {
63+
result,
64+
data: {
65+
result,
66+
},
67+
timestamps,
68+
},
69+
}
70+
})
71+
},
72+
})

0 commit comments

Comments
 (0)