Skip to content
Draft
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5c5c573
feature/CM-1099 Add prototype basic nav for liveArt
markhoangcll Aug 28, 2025
a64af31
feature/CM-1099 Update package json
markhoangcll Aug 28, 2025
ba0ef5c
feature/CM-1099 Fix the tests and add extra validations on the payloa…
markhoangcll Sep 4, 2025
e4bb691
CM-1099 Make changes according to some suggestions made in PR review
markhoangcll Sep 23, 2025
372f03f
CM-1099 Add more changes after PR review
markhoangcll Sep 29, 2025
05d634b
CM-1099 Add missing changes to address the PR comments
markhoangcll Sep 30, 2025
2cc1535
CM-1099 remove unnecessary config type, add error message in api resp…
markhoangcll Sep 30, 2025
4ad49a9
CM-1099 Fix param type for prepare and parse transport functions
markhoangcll Sep 30, 2025
7e6998c
Merge branch 'main' of github.com:smartcontractkit/external-adapters-…
markhoangcll Sep 30, 2025
a775786
CM-1120 add missing fields in the package root tsconfigs, restore for…
markhoangcll Oct 1, 2025
3406afd
CM-1099 restore ftse formatted files
markhoangcll Oct 1, 2025
41a1c4c
Merge branch 'main' into feature/CM-1099_liveart_ea_nav
markhoangcll Oct 2, 2025
ff5e8bf
Update .changeset/thirty-ducks-wait.md
mmcallister-cll Oct 3, 2025
e2c52cb
Update packages/sources/liveart/src/index.ts
mmcallister-cll Oct 3, 2025
2fae932
CM-1099 Change endpoint and transport definition to match the Jira sp…
markhoangcll Oct 21, 2025
3233279
Merge branch 'feature/CM-1099_liveart_ea_nav' of github.com:smartcont…
markhoangcll Oct 21, 2025
45dd724
Merge branch 'main' of github.com:smartcontractkit/external-adapters-…
markhoangcll Oct 21, 2025
d1d79e1
CM-1099 Restore accidental changes
markhoangcll Oct 21, 2025
a9a3faf
CM-1099 Restore accidental changes for this covid-tracker
markhoangcll Oct 21, 2025
731f1d7
CM-1099 Remove unneeded imports
markhoangcll Oct 21, 2025
90b6795
CM-1099 Add tests WIP
markhoangcll Oct 22, 2025
26d82b9
CM-1099 Update adapter to return nav_per_share value
markhoangcll Oct 29, 2025
b38beb2
CM-1099 Update package.json
markhoangcll Oct 29, 2025
415ee4e
CM-1099 Update hooks in tests
markhoangcll Oct 30, 2025
7e18493
Update .changeset/thirty-ducks-wait.md
mmcallister-cll Oct 31, 2025
a12dc0a
CM-1099 Add default production URL
markhoangcll Nov 3, 2025
e5062ff
Merge branch 'feature/CM-1099_liveart_ea_nav' of github.com:smartcont…
markhoangcll Nov 3, 2025
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
5 changes: 5 additions & 0 deletions .changeset/thirty-ducks-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/liveart-external-adapter': major
---

LiveArt EA initial release
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.

34 changes: 34 additions & 0 deletions packages/sources/liveart/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@chainlink/liveart-external-adapter",
"version": "1.0.0",
"description": "LiveArt NAV external adapter for Chainlink",
"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": {
"test": "echo \"Error: no test specified\" && exit 1",
"clean": "rm -rf dist && rm -f tsconfig.tsbuildinfo",
"prepack": "yarn build",
"build": "tsc -b",
"server": "node -e 'require(\"./src/index.ts\").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.8.0",
"tslib": "2.4.1"
}
}
10 changes: 10 additions & 0 deletions packages/sources/liveart/src/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { AdapterConfig } from '@chainlink/external-adapter-framework/config'

export const config: AdapterConfig = new AdapterConfig({
API_BASE_URL: {
description: 'The API URL for the LiveArt data provider',
type: 'string',
required: true,
default: 'https://artwork-price-oracle-api-dev-ms.liveart.ai',
Copy link
Contributor

Choose a reason for hiding this comment

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

this is their prod API?

},
})
25 changes: 25 additions & 0 deletions packages/sources/liveart/src/endpoint/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
import { InputParameters } from '@chainlink/external-adapter-framework/validation'

import { httpTransport } from '../transport/asset'

export const inputParameters = new InputParameters(
{
asset_id: {
required: true,
type: 'string',
description: 'The ID of the artwork asset to fetch',
},
},
[
{
asset_id: 'KUSPUM',
},
],
)

export const asset = new AdapterEndpoint({
name: 'asset',
transport: httpTransport,
inputParameters,
})
8 changes: 8 additions & 0 deletions packages/sources/liveart/src/endpoint/assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
import { httpTransport } from '../transport/assets'

// Assets endpoint has no input params
export const assets = new AdapterEndpoint({
name: 'assets',
transport: httpTransport,
})
15 changes: 15 additions & 0 deletions packages/sources/liveart/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
import { Adapter } from '@chainlink/external-adapter-framework/adapter'

import { config } from './config/config'
import { asset } from './endpoint/asset'
import { assets } from './endpoint/assets'

export const adapter = new Adapter({
defaultEndpoint: assets.name,
name: 'LIVE_ART',
config,
endpoints: [asset, assets],
})

export const server = (): Promise<ServerInstance | undefined> => expose(adapter)
56 changes: 56 additions & 0 deletions packages/sources/liveart/src/transport/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { HttpTransport } from '@chainlink/external-adapter-framework/transports/http'
import { TypeFromDefinition } from '@chainlink/external-adapter-framework/validation/input-params'
import { config } from '../config/config'
import { inputParameters } from '../endpoint/asset'
import { Asset } from './types'

export type BaseEndpointTypes = {
Parameters: typeof inputParameters.definition
Response: {
Data: Asset
Result: null
}
Settings: typeof config.settings
}

export type HttpTransportTypes = BaseEndpointTypes & {
Provider: {
RequestBody: never
ResponseBody: Asset
}
}

export const httpTransport = new HttpTransport<HttpTransportTypes>({
prepareRequests: (params, adapterSettings) => {
return params.map((param) => {
return {
params: [param],
request: {
baseURL: adapterSettings.API_BASE_URL,
url: `/asset/${param.asset_id}`,
},
}
})
},
parseResponse: (params, response) => {
return params.map((param: TypeFromDefinition<typeof inputParameters.definition>) => {
if (param.asset_id !== response.data.asset_id) {
return {
params: param,
response: {
errorMessage: `Mismatched asset_id in response. Expected ${param.asset_id}, got ${response.data.asset_id}`,
statusCode: 500,
},
}
}

return {
params: param,
response: {
result: null,
data: response.data,
},
}
})
},
})
44 changes: 44 additions & 0 deletions packages/sources/liveart/src/transport/assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { HttpTransport } from '@chainlink/external-adapter-framework/transports/http'
import { EmptyInputParameters } from '@chainlink/external-adapter-framework/validation/input-params'
import { config } from '../config/config'
import { Asset } from './types'

export type BaseEndpointTypes = {
Parameters: EmptyInputParameters
Response: {
Data: Asset[]
Result: null
}
Settings: typeof config.settings
}

export type HttpTransportTypes = BaseEndpointTypes & {
Provider: {
RequestBody: never
ResponseBody: Asset[]
}
}

export const httpTransport = new HttpTransport<HttpTransportTypes>({
prepareRequests: (params, adapterSettings) => {
return {
params,
request: {
baseURL: adapterSettings.baseURL,
url: '/assets',
method: 'GET',
},
}
},
parseResponse: (params, response) => {
return [
{
params,
response: {
data: response.data,
result: null,
},
},
]
},
})
17 changes: 17 additions & 0 deletions packages/sources/liveart/src/transport/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export interface Asset {
asset_id: string
asset_info_category: string
asset_info_creator: string
asset_info_title: string
asset_info_year_created: string
asset_info_description: string
asset_info_url: string
current_estimated_nav_usd: string
current_estimated_nav_updated_at: string
token_total_shares: number
token_current_estimated_nav_per_share_usd: string
offering_price_usd: string
success: boolean
message: string
response_timestamp: string
}
5 changes: 5 additions & 0 deletions packages/sources/liveart/test-payload.json
Copy link
Contributor

Choose a reason for hiding this comment

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

can remove

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"requests": [{
"artwork_id": "banksy"
}]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`LiveArt NAV endpoints /asset/\${asset_id} should handle upstream bad response 1`] = `
{
"data": {
"asset_id": "ROLSUB",
"asset_info_category": "",
"asset_info_creator": "",
"asset_info_description": "",
"asset_info_title": "",
"asset_info_url": "",
"asset_info_year_created": "",
"current_estimated_nav_updated_at": "",
"current_estimated_nav_usd": "",
"message": "Asset ID 'AssetId.ROLSUB' not found",
"offering_price_usd": "",
"response_timestamp": "2025-10-21T11:45:51.122126",
"success": false,
"token_current_estimated_nav_per_share_usd": "",
"token_total_shares": 0,
},
"result": null,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 978347471111,
"providerDataRequestedUnixMs": 978347471111,
},
}
`;

exports[`LiveArt NAV endpoints /asset/\${asset_id} should return success for valid asset_id 1`] = `
{
"data": {
"asset_id": "KUSPUM",
"asset_info_category": "Artwork",
"asset_info_creator": "Yayoi Kusama",
"asset_info_description": "Yayoi Kusama is a living legend whose polka-dotted universe has taken over museums, fashion, and the auction block—generating a $2.4B market cap. From MoMA to Louis Vuitton, her iconic Infinity Rooms and Pumpkin artworks have made her one of the most collected artists alive",
"asset_info_title": "Pumpkin (2)",
"asset_info_url": "https://liveart.io/analytics/artworks/wDigKX/yayoi-kusama",
"asset_info_year_created": "1990",
"current_estimated_nav_updated_at": "2025-10-13T08:50:09.546855",
"current_estimated_nav_usd": "67410.81654052",
"message": "",
"offering_price_usd": "70000.00000000",
"response_timestamp": "2025-10-20T13:01:12.095377",
"success": true,
"token_current_estimated_nav_per_share_usd": "0.09630117",
"token_total_shares": 700000,
},
"result": null,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 978347471111,
"providerDataRequestedUnixMs": 978347471111,
},
}
`;
Loading
Loading