From c7f4d469407b2f622e636c1d6bf8e76211d2dbb6 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 14 Nov 2025 17:03:30 -0500 Subject: [PATCH 1/8] OPDATA-4973 add address-adhoc endpoint to multi-address-list for diagnostic purposes --- .../src/endpoint/address-adhoc.ts | 14 +++ .../src/endpoint/address.ts | 58 +++++++----- .../multi-address-list/src/endpoint/index.ts | 1 + .../multi-address-list/src/index.ts | 6 +- .../src/transport/address-adhoc.ts | 66 ++++++++++++++ .../src/transport/address.ts | 84 ++--------------- .../src/transport/common.ts | 90 +++++++++++++++++++ .../adapter-noschedulemock.test.ts.snap | 61 +++++++++++++ .../adapter-noschedulemock.test.ts | 66 ++++++++++++++ .../test/integration/adapter.test.ts | 12 ++- 10 files changed, 347 insertions(+), 111 deletions(-) create mode 100644 packages/composites/multi-address-list/src/endpoint/address-adhoc.ts create mode 100644 packages/composites/multi-address-list/src/transport/address-adhoc.ts create mode 100644 packages/composites/multi-address-list/src/transport/common.ts create mode 100644 packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap create mode 100644 packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts diff --git a/packages/composites/multi-address-list/src/endpoint/address-adhoc.ts b/packages/composites/multi-address-list/src/endpoint/address-adhoc.ts new file mode 100644 index 0000000000..5299844f8b --- /dev/null +++ b/packages/composites/multi-address-list/src/endpoint/address-adhoc.ts @@ -0,0 +1,14 @@ +import { PoRAddressEndpoint } from '@chainlink/external-adapter-framework/adapter/por' +import { addressAdhocTransport } from '../transport/address-adhoc' +import { customInputValidation, inputParameters } from './address' + +/** + * This endpoint is meant to be used for debugging purposes + * and not for production feeds. + */ +export const endpoint = new PoRAddressEndpoint({ + name: 'address-adhoc', + transport: addressAdhocTransport, + inputParameters, + customInputValidation, +}) diff --git a/packages/composites/multi-address-list/src/endpoint/address.ts b/packages/composites/multi-address-list/src/endpoint/address.ts index 2dadb03b57..d029122828 100644 --- a/packages/composites/multi-address-list/src/endpoint/address.ts +++ b/packages/composites/multi-address-list/src/endpoint/address.ts @@ -1,14 +1,14 @@ -import { InputParameters } from '@chainlink/external-adapter-framework/validation' -import { config } from '../config' -import { addressListTransport } from '../transport/address' +import { walletParameters as anchorageParams } from '@chainlink/anchorage-adapter' +import { walletParameters as bitGoParams } from '@chainlink/bitgo-adapter' +import { walletParameters as coinbasePrimeParams } from '@chainlink/coinbase-prime-adapter' import { PoRAddressEndpoint, PoRAddressResponse, } from '@chainlink/external-adapter-framework/adapter/por' -import { walletParameters as anchorageParams } from '@chainlink/anchorage-adapter' -import { walletParameters as coinbasePrimeParams } from '@chainlink/coinbase-prime-adapter' -import { walletParameters as bitGoParams } from '@chainlink/bitgo-adapter' +import { InputParameters } from '@chainlink/external-adapter-framework/validation' import { AdapterInputError } from '@chainlink/external-adapter-framework/validation/error' +import { config } from '../config' +import { addressListTransport } from '../transport/address' export const inputParameters = new InputParameters({ chainId: { @@ -63,25 +63,37 @@ export type BaseEndpointTypes = { Settings: typeof config.settings } +type RequestType = { + requestContext: { + data: typeof inputParameters.validated + } +} + +export const customInputValidation = ( + request: RequestType, + adapterSettings: BaseEndpointTypes['Settings'], +): AdapterInputError | undefined => { + // Check if the required environment variables for source EAs are set. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { chainId, network, ...sources } = request.requestContext.data + + Object.keys(sources).forEach((source) => { + const envName = `${source.toUpperCase()}_ADAPTER_URL` as keyof typeof adapterSettings + const params = sources[source as keyof typeof sources] + if (params && !adapterSettings[envName]) { + throw new AdapterInputError({ + statusCode: 400, + message: `Error: missing environment variable ${envName}`, + }) + } + return + }) + return +} + export const endpoint = new PoRAddressEndpoint({ name: 'address', transport: addressListTransport, inputParameters, - customInputValidation: (request, adapterSettings): AdapterInputError | undefined => { - // Check if the required environment variables for source EAs are set. - const { chainId, network, ...sources } = request.requestContext.data - - Object.keys(sources).forEach((source) => { - const envName = `${source.toUpperCase()}_ADAPTER_URL` as keyof typeof adapterSettings - const params = sources[source as keyof typeof sources] - if (params && !adapterSettings[envName]) { - throw new AdapterInputError({ - statusCode: 400, - message: `Error: missing environment variable ${envName}`, - }) - } - return - }) - return - }, + customInputValidation, }) diff --git a/packages/composites/multi-address-list/src/endpoint/index.ts b/packages/composites/multi-address-list/src/endpoint/index.ts index 812dfe92f6..c89e477040 100644 --- a/packages/composites/multi-address-list/src/endpoint/index.ts +++ b/packages/composites/multi-address-list/src/endpoint/index.ts @@ -1 +1,2 @@ export { endpoint as address } from './address' +export { endpoint as addressAdhoc } from './address-adhoc' diff --git a/packages/composites/multi-address-list/src/index.ts b/packages/composites/multi-address-list/src/index.ts index 8796f87712..f444a5b6b4 100644 --- a/packages/composites/multi-address-list/src/index.ts +++ b/packages/composites/multi-address-list/src/index.ts @@ -1,13 +1,13 @@ import { expose, ServerInstance } from '@chainlink/external-adapter-framework' -import { config } from './config' -import { address } from './endpoint' import { PoRAdapter } from '@chainlink/external-adapter-framework/adapter/por' +import { config } from './config' +import { address, addressAdhoc } from './endpoint' export const adapter = new PoRAdapter({ defaultEndpoint: address.name, name: 'MULTI_ADDRESS_LIST', config, - endpoints: [address], + endpoints: [address, addressAdhoc], }) export const server = (): Promise => expose(adapter) diff --git a/packages/composites/multi-address-list/src/transport/address-adhoc.ts b/packages/composites/multi-address-list/src/transport/address-adhoc.ts new file mode 100644 index 0000000000..647f4621a4 --- /dev/null +++ b/packages/composites/multi-address-list/src/transport/address-adhoc.ts @@ -0,0 +1,66 @@ +import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' +import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' +import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' +import { AdapterResponse, makeLogger, sleep } from '@chainlink/external-adapter-framework/util' +import { Requester } from '@chainlink/external-adapter-framework/util/requester' +import { BaseEndpointTypes } from '../endpoint/address' +import { AddressListTransportTypes, BaseAddressListTransport, RequestParams } from './common' + +const logger = makeLogger('BaseAddressListTransport') + +export class AddressAdhocTransport extends BaseAddressListTransport { + name!: string + responseCache!: ResponseCache + requester!: Requester + settings!: AddressListTransportTypes['Settings'] + activeParams: RequestParams[] = [] + + async initialize( + dependencies: TransportDependencies, + adapterSettings: AddressListTransportTypes['Settings'], + endpointName: string, + transportName: string, + ): Promise { + await super.initialize(dependencies, adapterSettings, endpointName, transportName) + this.requester = dependencies.requester + this.settings = adapterSettings + } + + // backgroundHandler is used here to only update the subscription set and not to make the actual request. + // The actual request is made in the execute function by the scheduler. + async backgroundHandler( + context: EndpointContext, + entries: RequestParams[], + ) { + await Promise.all(entries.map(async (param) => this.handleRequest(param))) + await sleep(context.adapterSettings.BACKGROUND_EXECUTE_MS) + } + + async handleRequest(param: RequestParams) { + let response: AdapterResponse + try { + response = await this._handleRequest(param) + } catch (e) { + const errorMessage = e instanceof Error ? e.message : 'Unknown error occurred' + logger.error(e, errorMessage) + response = { + statusCode: 502, + errorMessage, + timestamps: { + providerDataRequestedUnixMs: 0, + providerDataReceivedUnixMs: 0, + providerIndicatedTimeUnixMs: undefined, + }, + } + } + await this.responseCache.write(this.name, [{ params: param, response }]) + } + + async _handleRequest( + param: RequestParams, + ): Promise> { + return this.getAggregatedAddressList(param) + } +} + +export const addressAdhocTransport = new AddressAdhocTransport() diff --git a/packages/composites/multi-address-list/src/transport/address.ts b/packages/composites/multi-address-list/src/transport/address.ts index 7465b87241..804b217847 100644 --- a/packages/composites/multi-address-list/src/transport/address.ts +++ b/packages/composites/multi-address-list/src/transport/address.ts @@ -1,35 +1,14 @@ -import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' +import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' -import { Requester } from '@chainlink/external-adapter-framework/util/requester' +import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' import { makeLogger, sleep } from '@chainlink/external-adapter-framework/util' -import { BaseEndpointTypes, inputParameters } from '../endpoint/address' +import { Requester } from '@chainlink/external-adapter-framework/util/requester' import schedule from 'node-schedule' -import { SubscriptionTransport } from '@chainlink/external-adapter-framework/transports/abstract/subscription' -import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' +import { AddressListTransportTypes, BaseAddressListTransport, RequestParams } from './common' const logger = makeLogger('AddressListTransport') -export type AddressListTransportTypes = BaseEndpointTypes - -type RequestParams = typeof inputParameters.validated - -interface PoRAdapterResponse { - data: { - result: { - network: string - chainId: string - address: string - }[] - } - statusCode: number - result: null - timestamps: { - providerDataRequestedUnixMs: number - providerDataReceivedUnixMs: number - } -} - -export class AddressListTransport extends SubscriptionTransport { +export class AddressListTransport extends BaseAddressListTransport { name!: string responseCache!: ResponseCache requester!: Requester @@ -76,29 +55,13 @@ export class AddressListTransport extends SubscriptionTransport= this.settings.MAX_RETRIES) { logger.error(`Max retry count reached for params: ${JSON.stringify(params)}`) return } try { - const addresses = await this.fetchSourceAddresses(params) - logger.info(`Fetched ${addresses.length} addresses`) - - const response = { - data: { - result: addresses, - }, - statusCode: 200, - result: null, - timestamps: { - providerDataRequestedUnixMs, - providerDataReceivedUnixMs: Date.now(), - providerIndicatedTimeUnixMs: undefined, - }, - } + const response = await this.getAggregatedAddressList(params) await this.responseCache.write(this.name, [ { params, @@ -111,41 +74,6 @@ export class AddressListTransport extends SubscriptionTransport this.execute(params, retryCount), this.settings.RETRY_INTERVAL_MS) } } - - async fetchSourceAddresses(params: RequestParams) { - const { chainId, network, ...sources } = params - - const promises = Object.entries(sources) - .filter(([_, sourceParams]) => sourceParams) - .map(async ([sourceName, sourceParams]) => { - // customInputValidation ensures that if the source EA is present in the input params, the corresponding env variable is also present - const adapterUrl = `${sourceName.toUpperCase()}_ADAPTER_URL` as keyof typeof this.settings - const requestConfig = { - url: this.settings[adapterUrl] as string, - method: 'POST', - data: { - data: { - ...sourceParams, - chainId: params.chainId, - network: params.network, - }, - }, - } - - const sourceResponse = await this.requester.request( - JSON.stringify(requestConfig), - requestConfig, - ) - return sourceResponse.response.data.data.result - }) - - const addresses = await Promise.all(promises) - return addresses.flat() - } - - getSubscriptionTtlFromConfig(adapterSettings: AddressListTransportTypes['Settings']): number { - return adapterSettings.WARMUP_SUBSCRIPTION_TTL - } } export const addressListTransport = new AddressListTransport() diff --git a/packages/composites/multi-address-list/src/transport/common.ts b/packages/composites/multi-address-list/src/transport/common.ts new file mode 100644 index 0000000000..0b7e44b57c --- /dev/null +++ b/packages/composites/multi-address-list/src/transport/common.ts @@ -0,0 +1,90 @@ +import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' +import { SubscriptionTransport } from '@chainlink/external-adapter-framework/transports/abstract/subscription' +import { makeLogger } from '@chainlink/external-adapter-framework/util' +import { Requester } from '@chainlink/external-adapter-framework/util/requester' +import { BaseEndpointTypes, inputParameters } from '../endpoint/address' + +const logger = makeLogger('BaseAddressListTransport') + +export type AddressListTransportTypes = BaseEndpointTypes +export type RequestParams = typeof inputParameters.validated + +interface PoRAdapterResponse { + data: { + result: { + network: string + chainId: string + address: string + }[] + } + statusCode: number + result: null + timestamps: { + providerDataRequestedUnixMs: number + providerDataReceivedUnixMs: number + } +} + +export abstract class BaseAddressListTransport extends SubscriptionTransport { + name!: string + responseCache!: ResponseCache + requester!: Requester + settings!: AddressListTransportTypes['Settings'] + activeParams: RequestParams[] = [] + + async getAggregatedAddressList(params: RequestParams) { + const providerDataRequestedUnixMs = Date.now() + + const addresses = await this.fetchSourceAddresses(params) + logger.info(`Fetched ${addresses.length} addresses`) + + const response = { + data: { + result: addresses, + }, + statusCode: 200, + result: null, + timestamps: { + providerDataRequestedUnixMs, + providerDataReceivedUnixMs: Date.now(), + providerIndicatedTimeUnixMs: undefined, + }, + } + return response + } + + async fetchSourceAddresses(params: RequestParams) { + const { chainId, network, ...sources } = params + + const promises = Object.entries(sources) + .filter(([_, sourceParams]) => sourceParams) + .map(async ([sourceName, sourceParams]) => { + // customInputValidation ensures that if the source EA is present in the input params, the corresponding env variable is also present + const adapterUrl = `${sourceName.toUpperCase()}_ADAPTER_URL` as keyof typeof this.settings + const requestConfig = { + url: this.settings[adapterUrl] as string, + method: 'POST', + data: { + data: { + ...sourceParams, + chainId, + network, + }, + }, + } + + const sourceResponse = await this.requester.request( + JSON.stringify(requestConfig), + requestConfig, + ) + return sourceResponse.response.data.data.result + }) + + const addresses = await Promise.all(promises) + return addresses.flat() + } + + getSubscriptionTtlFromConfig(adapterSettings: AddressListTransportTypes['Settings']): number { + return adapterSettings.WARMUP_SUBSCRIPTION_TTL + } +} diff --git a/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap b/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap new file mode 100644 index 0000000000..2282e3297e --- /dev/null +++ b/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`execute address-adhoc endpoint should return success 1`] = ` +{ + "data": { + "result": [ + { + "address": "bc2434567890123456789012345678901234567890", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "bc3534567890123456789012345678901234567890", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "bc4634567890123456789012345678901234567890", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "tb1q44alsfkysj4zxvwk6ktwjq3c0wysrxmunmxkh3n84dpqfg85l7msqn8a83", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "tb1qq93j04yg2klrfnfhhmr7k6ha0kz9qmm6p5gmrvhtpsc4l620h8cq8gzqfr", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "tb1qa5c93xvk45m34lqe52sfcu2ls9n7zexy9g9rhn6emzzr4t7hv35qwulqce", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "tb1qm4et3f642cct77s99zmwctl9mmdaemprwlndylpusl2lmesl62aq3kzg6s", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "bc0987654321098765432109876543210987654321", + "chainId": "mainnet", + "network": "bitcoin", + }, + { + "address": "bc1234567890123456789012345678901234567890", + "chainId": "mainnet", + "network": "bitcoin", + }, + ], + }, + "result": null, + "statusCode": 200, + "timestamps": { + "providerDataReceivedUnixMs": 978347471111, + "providerDataRequestedUnixMs": 978347471111, + }, +} +`; diff --git a/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts b/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts new file mode 100644 index 0000000000..b2b7f85623 --- /dev/null +++ b/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts @@ -0,0 +1,66 @@ +import { + TestAdapter, + setEnvVariables, +} from '@chainlink/external-adapter-framework/util/testing-utils' +import * as nock from 'nock' +import { mockAnchorageSuccess, mockBitgoSuccess, mockCBPSuccess } from './fixtures' + +describe('execute', () => { + let spy: jest.SpyInstance + let testAdapter: TestAdapter + let oldEnv: NodeJS.ProcessEnv + + beforeAll(async () => { + oldEnv = JSON.parse(JSON.stringify(process.env)) + process.env.ANCHORAGE_ADAPTER_URL = 'https://localhost:8081' + process.env.BITGO_ADAPTER_URL = 'https://localhost:8082' + process.env.COINBASE_PRIME_ADAPTER_URL = 'https://localhost:8083' + process.env.BACKGROUND_EXECUTE_MS = '0' + + 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('address-adhoc endpoint', () => { + it('should return success', async () => { + const data = { + endpoint: 'address-adhoc', + network: 'bitcoin', + chainId: 'mainnet', + anchorage: { + vaultId: 'b0bb5449c1e4926542ce693b4db2e883', + coin: 'BTC', + }, + bitgo: { + coin: 'tbtc', + enterpriseId: '1234', + }, + coinbase_prime: { + batchSize: 100, + portfolio: '12345622', + symbols: ['BTC'], + }, + } + mockAnchorageSuccess() + mockBitgoSuccess() + mockCBPSuccess() + const response = await testAdapter.request(data) + expect(response.statusCode).toBe(200) + expect(response.json()).toMatchSnapshot() + }) + }) +}) diff --git a/packages/composites/multi-address-list/test/integration/adapter.test.ts b/packages/composites/multi-address-list/test/integration/adapter.test.ts index 8aacf46f41..f8be1fe8d8 100644 --- a/packages/composites/multi-address-list/test/integration/adapter.test.ts +++ b/packages/composites/multi-address-list/test/integration/adapter.test.ts @@ -3,8 +3,8 @@ import { setEnvVariables, } from '@chainlink/external-adapter-framework/util/testing-utils' import * as nock from 'nock' -import { mockAnchorageSuccess, mockBitgoSuccess, mockCBPSuccess } from './fixtures' import { RecurrenceRule } from 'node-schedule' +import { mockAnchorageSuccess, mockBitgoSuccess, mockCBPSuccess } from './fixtures' jest.mock('node-schedule', () => { const actualNodeSchedule = jest.requireActual('node-schedule') @@ -28,12 +28,10 @@ describe('execute', () => { beforeAll(async () => { oldEnv = JSON.parse(JSON.stringify(process.env)) - process.env.ANCHORAGE_ADAPTER_URL = - process.env.ANCHORAGE_ADAPTER_URL ?? 'https://localhost:8081' - process.env.BITGO_ADAPTER_URL = process.env.BITGO_ADAPTER_URL ?? 'https://localhost:8082' - process.env.COINBASE_PRIME_ADAPTER_URL = - process.env.COINBASE_PRIME_ADAPTER_URL ?? 'https://localhost:8083' - process.env.BACKGROUND_EXECUTE_MS = process.env.BACKGROUND_EXECUTE_MS ?? '0' + process.env.ANCHORAGE_ADAPTER_URL = 'https://localhost:8081' + process.env.BITGO_ADAPTER_URL = 'https://localhost:8082' + process.env.COINBASE_PRIME_ADAPTER_URL = 'https://localhost:8083' + process.env.BACKGROUND_EXECUTE_MS = '0' const mockDate = new Date('2001-01-01T11:11:11.111Z') spy = jest.spyOn(Date, 'now').mockReturnValue(mockDate.getTime()) From 0920006790e84486e9f158f7c5c0734e7bcc692b Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 14 Nov 2025 17:04:10 -0500 Subject: [PATCH 2/8] add changeset --- .changeset/two-numbers-confess.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/two-numbers-confess.md diff --git a/.changeset/two-numbers-confess.md b/.changeset/two-numbers-confess.md new file mode 100644 index 0000000000..aea5832828 --- /dev/null +++ b/.changeset/two-numbers-confess.md @@ -0,0 +1,5 @@ +--- +'@chainlink/multi-address-list-adapter': minor +--- + +added address-adhoc endpoint From b15a24ee5cedf425aab0595a809ab06a4265fdb4 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 14 Nov 2025 17:13:06 -0500 Subject: [PATCH 3/8] remove copy pasta comment --- .../multi-address-list/src/transport/address-adhoc.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/composites/multi-address-list/src/transport/address-adhoc.ts b/packages/composites/multi-address-list/src/transport/address-adhoc.ts index 647f4621a4..9ca7e31246 100644 --- a/packages/composites/multi-address-list/src/transport/address-adhoc.ts +++ b/packages/composites/multi-address-list/src/transport/address-adhoc.ts @@ -26,8 +26,6 @@ export class AddressAdhocTransport extends BaseAddressListTransport { this.settings = adapterSettings } - // backgroundHandler is used here to only update the subscription set and not to make the actual request. - // The actual request is made in the execute function by the scheduler. async backgroundHandler( context: EndpointContext, entries: RequestParams[], From 1898a975faf30f49caa3db22c0c55189e6ddc29f Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 14 Nov 2025 17:15:18 -0500 Subject: [PATCH 4/8] update to latest framework version --- .pnp.cjs | 2 +- packages/composites/multi-address-list/package.json | 2 +- yarn.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pnp.cjs b/.pnp.cjs index 600c7d3e01..f75743c014 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -8016,7 +8016,7 @@ const RAW_RUNTIME_STATE = ["@chainlink/anchorage-adapter", "workspace:packages/sources/anchorage"],\ ["@chainlink/bitgo-adapter", "workspace:packages/sources/bitgo"],\ ["@chainlink/coinbase-prime-adapter", "workspace:packages/sources/coinbase-prime"],\ - ["@chainlink/external-adapter-framework", "npm:2.8.0"],\ + ["@chainlink/external-adapter-framework", "npm:2.11.0"],\ ["@types/jest", "npm:29.5.14"],\ ["@types/node", "npm:22.14.1"],\ ["@types/node-schedule", "npm:2.1.7"],\ diff --git a/packages/composites/multi-address-list/package.json b/packages/composites/multi-address-list/package.json index d49ea197e6..2cd4c50d6b 100644 --- a/packages/composites/multi-address-list/package.json +++ b/packages/composites/multi-address-list/package.json @@ -38,7 +38,7 @@ "@chainlink/anchorage-adapter": "workspace:*", "@chainlink/bitgo-adapter": "workspace:*", "@chainlink/coinbase-prime-adapter": "workspace:*", - "@chainlink/external-adapter-framework": "2.8.0", + "@chainlink/external-adapter-framework": "2.11.0", "node-schedule": "2.1.1", "tslib": "2.4.1" } diff --git a/yarn.lock b/yarn.lock index 865e9c56a9..e80a5cb77f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5002,7 +5002,7 @@ __metadata: "@chainlink/anchorage-adapter": "workspace:*" "@chainlink/bitgo-adapter": "workspace:*" "@chainlink/coinbase-prime-adapter": "workspace:*" - "@chainlink/external-adapter-framework": "npm:2.8.0" + "@chainlink/external-adapter-framework": "npm:2.11.0" "@types/jest": "npm:^29.5.14" "@types/node": "npm:22.14.1" "@types/node-schedule": "npm:2.1.7" From 9fa5266908c8ad0d77f2765d1d0aa2fc65498e3d Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 14 Nov 2025 17:19:29 -0500 Subject: [PATCH 5/8] rename address-adhoc to address-debug --- .changeset/two-numbers-confess.md | 2 +- .../endpoint/{address-adhoc.ts => address-debug.ts} | 10 +++++----- .../multi-address-list/src/endpoint/index.ts | 2 +- packages/composites/multi-address-list/src/index.ts | 4 ++-- .../transport/{address-adhoc.ts => address-debug.ts} | 4 ++-- .../__snapshots__/adapter-noschedulemock.test.ts.snap | 2 +- .../test/integration/adapter-noschedulemock.test.ts | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) rename packages/composites/multi-address-list/src/endpoint/{address-adhoc.ts => address-debug.ts} (53%) rename packages/composites/multi-address-list/src/transport/{address-adhoc.ts => address-debug.ts} (94%) diff --git a/.changeset/two-numbers-confess.md b/.changeset/two-numbers-confess.md index aea5832828..96f2e8e2fe 100644 --- a/.changeset/two-numbers-confess.md +++ b/.changeset/two-numbers-confess.md @@ -2,4 +2,4 @@ '@chainlink/multi-address-list-adapter': minor --- -added address-adhoc endpoint +added address-debug endpoint diff --git a/packages/composites/multi-address-list/src/endpoint/address-adhoc.ts b/packages/composites/multi-address-list/src/endpoint/address-debug.ts similarity index 53% rename from packages/composites/multi-address-list/src/endpoint/address-adhoc.ts rename to packages/composites/multi-address-list/src/endpoint/address-debug.ts index 5299844f8b..c187b17926 100644 --- a/packages/composites/multi-address-list/src/endpoint/address-adhoc.ts +++ b/packages/composites/multi-address-list/src/endpoint/address-debug.ts @@ -1,14 +1,14 @@ import { PoRAddressEndpoint } from '@chainlink/external-adapter-framework/adapter/por' -import { addressAdhocTransport } from '../transport/address-adhoc' +import { addressDebugTransport } from '../transport/address-debug' import { customInputValidation, inputParameters } from './address' /** - * This endpoint is meant to be used for debugging purposes - * and not for production feeds. + * This endpoint is meant to be used for debug/diagnostic + * purposes and not for production feeds. */ export const endpoint = new PoRAddressEndpoint({ - name: 'address-adhoc', - transport: addressAdhocTransport, + name: 'address-debug', + transport: addressDebugTransport, inputParameters, customInputValidation, }) diff --git a/packages/composites/multi-address-list/src/endpoint/index.ts b/packages/composites/multi-address-list/src/endpoint/index.ts index c89e477040..daa2939370 100644 --- a/packages/composites/multi-address-list/src/endpoint/index.ts +++ b/packages/composites/multi-address-list/src/endpoint/index.ts @@ -1,2 +1,2 @@ export { endpoint as address } from './address' -export { endpoint as addressAdhoc } from './address-adhoc' +export { endpoint as addressDebug } from './address-debug' diff --git a/packages/composites/multi-address-list/src/index.ts b/packages/composites/multi-address-list/src/index.ts index f444a5b6b4..0345fb15db 100644 --- a/packages/composites/multi-address-list/src/index.ts +++ b/packages/composites/multi-address-list/src/index.ts @@ -1,13 +1,13 @@ import { expose, ServerInstance } from '@chainlink/external-adapter-framework' import { PoRAdapter } from '@chainlink/external-adapter-framework/adapter/por' import { config } from './config' -import { address, addressAdhoc } from './endpoint' +import { address, addressDebug } from './endpoint' export const adapter = new PoRAdapter({ defaultEndpoint: address.name, name: 'MULTI_ADDRESS_LIST', config, - endpoints: [address, addressAdhoc], + endpoints: [address, addressDebug], }) export const server = (): Promise => expose(adapter) diff --git a/packages/composites/multi-address-list/src/transport/address-adhoc.ts b/packages/composites/multi-address-list/src/transport/address-debug.ts similarity index 94% rename from packages/composites/multi-address-list/src/transport/address-adhoc.ts rename to packages/composites/multi-address-list/src/transport/address-debug.ts index 9ca7e31246..b22872a987 100644 --- a/packages/composites/multi-address-list/src/transport/address-adhoc.ts +++ b/packages/composites/multi-address-list/src/transport/address-debug.ts @@ -8,7 +8,7 @@ import { AddressListTransportTypes, BaseAddressListTransport, RequestParams } fr const logger = makeLogger('BaseAddressListTransport') -export class AddressAdhocTransport extends BaseAddressListTransport { +export class AddressDebugTransport extends BaseAddressListTransport { name!: string responseCache!: ResponseCache requester!: Requester @@ -61,4 +61,4 @@ export class AddressAdhocTransport extends BaseAddressListTransport { } } -export const addressAdhocTransport = new AddressAdhocTransport() +export const addressDebugTransport = new AddressDebugTransport() diff --git a/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap b/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap index 2282e3297e..77ea406153 100644 --- a/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap +++ b/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`execute address-adhoc endpoint should return success 1`] = ` +exports[`execute address-debug endpoint should return success 1`] = ` { "data": { "result": [ diff --git a/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts b/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts index b2b7f85623..3bc38d74f2 100644 --- a/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts +++ b/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts @@ -35,10 +35,10 @@ describe('execute', () => { spy.mockRestore() }) - describe('address-adhoc endpoint', () => { + describe('address-debug endpoint', () => { it('should return success', async () => { const data = { - endpoint: 'address-adhoc', + endpoint: 'address-debug', network: 'bitcoin', chainId: 'mainnet', anchorage: { From 62bef07b3f5423d017c489c16eec69acf706dd57 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 14 Nov 2025 17:27:57 -0500 Subject: [PATCH 6/8] put back existing EA framework to avoid dependency spiral --- .pnp.cjs | 2 +- packages/composites/multi-address-list/package.json | 2 +- yarn.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pnp.cjs b/.pnp.cjs index f75743c014..600c7d3e01 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -8016,7 +8016,7 @@ const RAW_RUNTIME_STATE = ["@chainlink/anchorage-adapter", "workspace:packages/sources/anchorage"],\ ["@chainlink/bitgo-adapter", "workspace:packages/sources/bitgo"],\ ["@chainlink/coinbase-prime-adapter", "workspace:packages/sources/coinbase-prime"],\ - ["@chainlink/external-adapter-framework", "npm:2.11.0"],\ + ["@chainlink/external-adapter-framework", "npm:2.8.0"],\ ["@types/jest", "npm:29.5.14"],\ ["@types/node", "npm:22.14.1"],\ ["@types/node-schedule", "npm:2.1.7"],\ diff --git a/packages/composites/multi-address-list/package.json b/packages/composites/multi-address-list/package.json index 2cd4c50d6b..d49ea197e6 100644 --- a/packages/composites/multi-address-list/package.json +++ b/packages/composites/multi-address-list/package.json @@ -38,7 +38,7 @@ "@chainlink/anchorage-adapter": "workspace:*", "@chainlink/bitgo-adapter": "workspace:*", "@chainlink/coinbase-prime-adapter": "workspace:*", - "@chainlink/external-adapter-framework": "2.11.0", + "@chainlink/external-adapter-framework": "2.8.0", "node-schedule": "2.1.1", "tslib": "2.4.1" } diff --git a/yarn.lock b/yarn.lock index e80a5cb77f..865e9c56a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5002,7 +5002,7 @@ __metadata: "@chainlink/anchorage-adapter": "workspace:*" "@chainlink/bitgo-adapter": "workspace:*" "@chainlink/coinbase-prime-adapter": "workspace:*" - "@chainlink/external-adapter-framework": "npm:2.11.0" + "@chainlink/external-adapter-framework": "npm:2.8.0" "@types/jest": "npm:^29.5.14" "@types/node": "npm:22.14.1" "@types/node-schedule": "npm:2.1.7" From 964860cc15af532d298999b98e2394530cd64ee3 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Mon, 22 Dec 2025 17:31:01 -0500 Subject: [PATCH 7/8] update & refactor to use foreground execute --- .../src/endpoint/address-debug.ts | 2 + .../src/transport/address-debug.ts | 35 +++--- .../src/transport/address.ts | 11 +- .../src/transport/common.ts | 106 +++++++++--------- .../adapter-noschedulemock.test.ts.snap | 11 ++ .../adapter-noschedulemock.test.ts | 52 +++++---- .../test/integration/fixtures.ts | 31 ++++- 7 files changed, 154 insertions(+), 94 deletions(-) diff --git a/packages/composites/multi-address-list/src/endpoint/address-debug.ts b/packages/composites/multi-address-list/src/endpoint/address-debug.ts index c187b17926..739e2f3b50 100644 --- a/packages/composites/multi-address-list/src/endpoint/address-debug.ts +++ b/packages/composites/multi-address-list/src/endpoint/address-debug.ts @@ -5,6 +5,8 @@ import { customInputValidation, inputParameters } from './address' /** * This endpoint is meant to be used for debug/diagnostic * purposes and not for production feeds. + * Additionally, this endpoint will not contain a + * meta field in its response. */ export const endpoint = new PoRAddressEndpoint({ name: 'address-debug', diff --git a/packages/composites/multi-address-list/src/transport/address-debug.ts b/packages/composites/multi-address-list/src/transport/address-debug.ts index b22872a987..7eda74af11 100644 --- a/packages/composites/multi-address-list/src/transport/address-debug.ts +++ b/packages/composites/multi-address-list/src/transport/address-debug.ts @@ -1,14 +1,17 @@ -import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' -import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' -import { AdapterResponse, makeLogger, sleep } from '@chainlink/external-adapter-framework/util' +import { Transport, TransportDependencies } from '@chainlink/external-adapter-framework/transports' +import { + AdapterRequest, + AdapterResponse, + makeLogger, +} from '@chainlink/external-adapter-framework/util' import { Requester } from '@chainlink/external-adapter-framework/util/requester' -import { BaseEndpointTypes } from '../endpoint/address' -import { AddressListTransportTypes, BaseAddressListTransport, RequestParams } from './common' +import { BaseEndpointTypes, inputParameters } from '../endpoint/address' +import { AddressListTransportTypes, getAggregatedAddressList, RequestParams } from './common' const logger = makeLogger('BaseAddressListTransport') -export class AddressDebugTransport extends BaseAddressListTransport { +export class AddressDebugTransport implements Transport { name!: string responseCache!: ResponseCache requester!: Requester @@ -18,20 +21,20 @@ export class AddressDebugTransport extends BaseAddressListTransport { async initialize( dependencies: TransportDependencies, adapterSettings: AddressListTransportTypes['Settings'], - endpointName: string, + _endpointName: string, transportName: string, ): Promise { - await super.initialize(dependencies, adapterSettings, endpointName, transportName) this.requester = dependencies.requester + this.responseCache = dependencies.responseCache this.settings = adapterSettings + this.name = transportName } - async backgroundHandler( - context: EndpointContext, - entries: RequestParams[], - ) { - await Promise.all(entries.map(async (param) => this.handleRequest(param))) - await sleep(context.adapterSettings.BACKGROUND_EXECUTE_MS) + async foregroundExecute( + req: AdapterRequest, + ): Promise> { + const entries = req.requestContext.data + return await this.handleRequest(entries) } async handleRequest(param: RequestParams) { @@ -51,13 +54,13 @@ export class AddressDebugTransport extends BaseAddressListTransport { }, } } - await this.responseCache.write(this.name, [{ params: param, response }]) + return response } async _handleRequest( param: RequestParams, ): Promise> { - return this.getAggregatedAddressList(param) + return getAggregatedAddressList(param, this.requester, this.settings) } } diff --git a/packages/composites/multi-address-list/src/transport/address.ts b/packages/composites/multi-address-list/src/transport/address.ts index 804b217847..7ad28e7fc0 100644 --- a/packages/composites/multi-address-list/src/transport/address.ts +++ b/packages/composites/multi-address-list/src/transport/address.ts @@ -1,14 +1,15 @@ import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' +import { SubscriptionTransport } from '@chainlink/external-adapter-framework/transports/abstract/subscription' import { makeLogger, sleep } from '@chainlink/external-adapter-framework/util' import { Requester } from '@chainlink/external-adapter-framework/util/requester' import schedule from 'node-schedule' -import { AddressListTransportTypes, BaseAddressListTransport, RequestParams } from './common' +import { AddressListTransportTypes, getAggregatedAddressList, RequestParams } from './common' const logger = makeLogger('AddressListTransport') -export class AddressListTransport extends BaseAddressListTransport { +export class AddressListTransport extends SubscriptionTransport { name!: string responseCache!: ResponseCache requester!: Requester @@ -61,7 +62,7 @@ export class AddressListTransport extends BaseAddressListTransport { } try { - const response = await this.getAggregatedAddressList(params) + const response = await getAggregatedAddressList(params, this.requester, this.settings) await this.responseCache.write(this.name, [ { params, @@ -74,6 +75,10 @@ export class AddressListTransport extends BaseAddressListTransport { setTimeout(() => this.execute(params, retryCount), this.settings.RETRY_INTERVAL_MS) } } + + getSubscriptionTtlFromConfig(adapterSettings: AddressListTransportTypes['Settings']): number { + return adapterSettings.WARMUP_SUBSCRIPTION_TTL + } } export const addressListTransport = new AddressListTransport() diff --git a/packages/composites/multi-address-list/src/transport/common.ts b/packages/composites/multi-address-list/src/transport/common.ts index 0b7e44b57c..b635fe8a36 100644 --- a/packages/composites/multi-address-list/src/transport/common.ts +++ b/packages/composites/multi-address-list/src/transport/common.ts @@ -1,5 +1,4 @@ -import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' -import { SubscriptionTransport } from '@chainlink/external-adapter-framework/transports/abstract/subscription' +import { AdapterSettings } from '@chainlink/external-adapter-framework/config' import { makeLogger } from '@chainlink/external-adapter-framework/util' import { Requester } from '@chainlink/external-adapter-framework/util/requester' import { BaseEndpointTypes, inputParameters } from '../endpoint/address' @@ -25,66 +24,63 @@ interface PoRAdapterResponse { } } -export abstract class BaseAddressListTransport extends SubscriptionTransport { - name!: string - responseCache!: ResponseCache - requester!: Requester - settings!: AddressListTransportTypes['Settings'] - activeParams: RequestParams[] = [] +export async function getAggregatedAddressList( + params: RequestParams, + requester: Requester, + settings: AdapterSettings, +) { + const providerDataRequestedUnixMs = Date.now() - async getAggregatedAddressList(params: RequestParams) { - const providerDataRequestedUnixMs = Date.now() + const addresses = await fetchSourceAddresses(params, requester, settings) + logger.info(`Fetched ${addresses.length} addresses`) - const addresses = await this.fetchSourceAddresses(params) - logger.info(`Fetched ${addresses.length} addresses`) - - const response = { - data: { - result: addresses, - }, - statusCode: 200, - result: null, - timestamps: { - providerDataRequestedUnixMs, - providerDataReceivedUnixMs: Date.now(), - providerIndicatedTimeUnixMs: undefined, - }, - } - return response + const response = { + data: { + result: addresses, + }, + statusCode: 200, + result: null, + timestamps: { + providerDataRequestedUnixMs, + providerDataReceivedUnixMs: Date.now(), + providerIndicatedTimeUnixMs: undefined, + }, } + return response +} - async fetchSourceAddresses(params: RequestParams) { - const { chainId, network, ...sources } = params +async function fetchSourceAddresses( + params: RequestParams, + requester: Requester, + settings: AdapterSettings, +) { + const { chainId, network, ...sources } = params - const promises = Object.entries(sources) - .filter(([_, sourceParams]) => sourceParams) - .map(async ([sourceName, sourceParams]) => { - // customInputValidation ensures that if the source EA is present in the input params, the corresponding env variable is also present - const adapterUrl = `${sourceName.toUpperCase()}_ADAPTER_URL` as keyof typeof this.settings - const requestConfig = { - url: this.settings[adapterUrl] as string, - method: 'POST', + const promises = Object.entries(sources) + .filter(([_, sourceParams]) => sourceParams) + .map(async ([sourceName, sourceParams]) => { + // customInputValidation ensures that if the source EA is present in the input params, the corresponding env variable is also present + const adapterUrl = `${sourceName.toUpperCase()}_ADAPTER_URL` as keyof typeof settings + const requestConfig = { + url: settings[adapterUrl] as string, + // url: process.env(adapterUrl) + method: 'POST', + data: { data: { - data: { - ...sourceParams, - chainId, - network, - }, + ...sourceParams, + chainId, + network, }, - } + }, + } - const sourceResponse = await this.requester.request( - JSON.stringify(requestConfig), - requestConfig, - ) - return sourceResponse.response.data.data.result - }) + const sourceResponse = await requester.request( + JSON.stringify(requestConfig), + requestConfig, + ) + return sourceResponse.response.data.data.result + }) - const addresses = await Promise.all(promises) - return addresses.flat() - } - - getSubscriptionTtlFromConfig(adapterSettings: AddressListTransportTypes['Settings']): number { - return adapterSettings.WARMUP_SUBSCRIPTION_TTL - } + const addresses = await Promise.all(promises) + return addresses.flat() } diff --git a/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap b/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap index 77ea406153..838da59dfc 100644 --- a/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap +++ b/packages/composites/multi-address-list/test/integration/__snapshots__/adapter-noschedulemock.test.ts.snap @@ -1,5 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`execute address-debug endpoint should fail when missing underlying data source does not respond 1`] = ` +{ + "errorMessage": "Request failed with status code 504", + "statusCode": 502, + "timestamps": { + "providerDataReceivedUnixMs": 0, + "providerDataRequestedUnixMs": 0, + }, +} +`; + exports[`execute address-debug endpoint should return success 1`] = ` { "data": { diff --git a/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts b/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts index 3bc38d74f2..e5fddf0028 100644 --- a/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts +++ b/packages/composites/multi-address-list/test/integration/adapter-noschedulemock.test.ts @@ -3,13 +3,32 @@ import { setEnvVariables, } from '@chainlink/external-adapter-framework/util/testing-utils' import * as nock from 'nock' -import { mockAnchorageSuccess, mockBitgoSuccess, mockCBPSuccess } from './fixtures' +import { mockAnchorageSuccess, mockBitgoSuccess, mockCBPFailure, mockCBPSuccess } from './fixtures' describe('execute', () => { let spy: jest.SpyInstance let testAdapter: TestAdapter let oldEnv: NodeJS.ProcessEnv + const data = { + endpoint: 'address-debug', + network: 'bitcoin', + chainId: 'mainnet', + anchorage: { + vaultId: 'b0bb5449c1e4926542ce693b4db2e883', + coin: 'BTC', + }, + bitgo: { + coin: 'tbtc', + enterpriseId: '1234', + }, + coinbase_prime: { + batchSize: 100, + portfolio: '12345622', + symbols: ['BTC'], + }, + } + beforeAll(async () => { oldEnv = JSON.parse(JSON.stringify(process.env)) process.env.ANCHORAGE_ADAPTER_URL = 'https://localhost:8081' @@ -27,6 +46,11 @@ describe('execute', () => { }) }) + afterEach(async () => { + nock.cleanAll() + testAdapter.mockCache?.cache.clear() + }) + afterAll(async () => { setEnvVariables(oldEnv) await testAdapter.api.close() @@ -37,24 +61,6 @@ describe('execute', () => { describe('address-debug endpoint', () => { it('should return success', async () => { - const data = { - endpoint: 'address-debug', - network: 'bitcoin', - chainId: 'mainnet', - anchorage: { - vaultId: 'b0bb5449c1e4926542ce693b4db2e883', - coin: 'BTC', - }, - bitgo: { - coin: 'tbtc', - enterpriseId: '1234', - }, - coinbase_prime: { - batchSize: 100, - portfolio: '12345622', - symbols: ['BTC'], - }, - } mockAnchorageSuccess() mockBitgoSuccess() mockCBPSuccess() @@ -62,5 +68,13 @@ describe('execute', () => { expect(response.statusCode).toBe(200) expect(response.json()).toMatchSnapshot() }) + it('should fail when missing underlying data source does not respond', async () => { + mockAnchorageSuccess() + mockBitgoSuccess() + mockCBPFailure() + const response = await testAdapter.request(data) + expect(response.statusCode).toBe(502) + expect(response.json()).toMatchSnapshot() + }) }) }) diff --git a/packages/composites/multi-address-list/test/integration/fixtures.ts b/packages/composites/multi-address-list/test/integration/fixtures.ts index d54683cf43..9dadb95ed1 100644 --- a/packages/composites/multi-address-list/test/integration/fixtures.ts +++ b/packages/composites/multi-address-list/test/integration/fixtures.ts @@ -134,7 +134,7 @@ export const mockCBPSuccess = (): nock.Scope => nock('https://localhost:8083', { encodedQueryParams: true, }) - .persist() + // .persist() .post('/', { data: { batchSize: 100, @@ -190,3 +190,32 @@ export const mockCBPSuccess = (): nock.Scope => ], ) .persist() + +export const mockCBPFailure = (): nock.Scope => + nock('https://localhost:8083', { + encodedQueryParams: true, + }) + // .persist() + .post('/', { + data: { + batchSize: 100, + chainId: 'mainnet', + network: 'bitcoin', + portfolio: '12345622', + type: 'vault', + apiKey: '', + symbols: ['BTC'], + endpoint: 'wallet', + }, + }) + .reply(504, () => ({}), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + .persist() From f6b7109052aa003b833c3d85665f24c9f5f4a374 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Mon, 22 Dec 2025 17:40:07 -0500 Subject: [PATCH 8/8] remove commented line --- packages/composites/multi-address-list/src/transport/common.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/composites/multi-address-list/src/transport/common.ts b/packages/composites/multi-address-list/src/transport/common.ts index b635fe8a36..15889e6044 100644 --- a/packages/composites/multi-address-list/src/transport/common.ts +++ b/packages/composites/multi-address-list/src/transport/common.ts @@ -63,7 +63,6 @@ async function fetchSourceAddresses( const adapterUrl = `${sourceName.toUpperCase()}_ADAPTER_URL` as keyof typeof settings const requestConfig = { url: settings[adapterUrl] as string, - // url: process.env(adapterUrl) method: 'POST', data: { data: {