Skip to content

Implement price in six#4961

Open
mxiao-cll wants to merge 2 commits into
mainfrom
six
Open

Implement price in six#4961
mxiao-cll wants to merge 2 commits into
mainfrom
six

Conversation

@mxiao-cll
Copy link
Copy Markdown
Contributor

@mxiao-cll mxiao-cll commented May 13, 2026

Closes #OPDATA-6773

Implement the price endpoint with the following special cases:

  • Six's ws server may appear to be working but stopped streaming data, this is detectable via ping/pong. We implemented a timer that if pong comes 2 seconds after ping, we re-start the connection.
  • Six only stream updates on data that has updates, for example, if there is only updates on bid it will only stream a message containing the bid information. We are expected to use the previous ask information to form the full bid/ask pair. We implemented a cache locally to store the latest bid and ask as they come-in. When generating response, we fetch data from cache.
  • Six stream both lastPrice and bid/ask in one connection, thus we need to implement the stock & stock_quotes sharing a single ws connection
    • One endpoint with stock and stock_quotes alias with one ws transport
    • Inject the real endpoint name via framework into a hidden param
    • The transport will write data for stock or stock_quotes based on the messages streaming in
    • We will be able to match the response by using hidden param
    • The endpoint will return different data based on endpoint: stock vs endpoint: stock_quotes
    • We additionally dedupe the subscribe and un-subscribe message so only 1 is sent even when we request data on both endpoints
  • Message over 300 seconds old is rejected

Quality Assurance

  • If a new adapter was made, or an existing one was modified so that its environment variables have changed, update the relevant infra-k8s configuration file.
  • If a new adapter was made, or an existing one was modified so that its environment variables have changed, update the relevant adapter-secrets configuration file.
  • If a new adapter was made, or a new endpoint was added, update the test-payload.json file with relevant requests.
  • The branch naming follows git flow (feature/x, chore/x, release/x, hotfix/x, fix/x) or is created from Jira.
  • This is related to a maximum of one Jira story or GitHub issue.
  • Types are safe (avoid TypeScript/TSLint features like any and disable, instead use more specific types).
  • All code changes have 100% unit and integration test coverage. If testing is not applicable or too difficult to justify doing, the reasoning should be documented explicitly in the PR.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 13, 2026

🦋 Changeset detected

Latest commit: 7d11376

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@chainlink/six-adapter Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mxiao-cll mxiao-cll requested review from a team and dskloetc and removed request for dskloetc May 13, 2026 20:22
Comment thread packages/sources/six/src/endpoint/stock.ts
message: 'base must be in the format of ${TICKER}_${MARKET}',
})
}
req.requestContext.data.rawEndpoint = req.requestContext.requestEndpointName
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need this? Is the requestContext not also available in the transport?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We need to inject the raw endpoint into the request itself because we need it to match the cache key when we generate the response from ws messages.

Another way to do it would be to modify the base itself to include the endpoint names


1 request comes in, it will be able to generate two cache entries, the two cache entry need to have different cache key, so we need something more than the request itself to distinguish (here adding a new param into request)

export const inputParameters = new InputParameters(
{
...stockEndpointInputParametersDefinition,
rawEndpoint: {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this available in the params? Isn't it provided by the framework?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Framework strip endpoint out before passing it down, so we don't have access to that here.

const volume = msg?.size
const time = coverTimeToMs(msg?.unixTimestamp)

if (isMessageOld(time)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does it matter how old it is? If there are no newer messages it's still the most recent data, isn't it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think here we are preventing server from re-playing an old message, we don't have anything like this in our other ws. This comes from SA as

it is not a client or product’s requirement. we added it as a security measure to avoid writing stale data. if this is already managed elsewhere, feel free to remove that business logic from the adapter.

Can remove it if we think this is not important

Comment thread packages/sources/six/src/transport/price-cache.ts Outdated
Comment thread packages/sources/six/src/transport/price.ts Outdated
Comment thread packages/sources/six/src/transport/price.ts Outdated
Comment thread packages/sources/six/src/index.ts Outdated
Comment thread .changeset/true-sides-wait.md
setEnvVariables,
TestAdapter,
} from '@chainlink/external-adapter-framework/util/testing-utils'
import FakeTimers from '@sinonjs/fake-timers'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why use sinon fake timers rather than stubbing Date.now or jest.useFakeTimers like we normally do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

FakeTimers also widely used in our codebase

@mxiao-cll mxiao-cll requested a review from dskloetc May 15, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants