From 0b2333b624a148128ddc950daa7f16f92907f75c Mon Sep 17 00:00:00 2001 From: ConjunctiveNormalForm Date: Wed, 8 Nov 2023 11:46:24 -0500 Subject: [PATCH 1/5] add filler compliance provider --- lib/constants.ts | 2 + lib/handlers/quote/injector.ts | 19 ++++++- lib/providers/compliance/index.ts | 12 ++++ lib/providers/compliance/mock.ts | 24 ++++++++ lib/providers/compliance/s3.ts | 60 ++++++++++++++++++++ lib/quoters/WebhookQuoter.ts | 15 +++++ test/handlers/quote/handler.test.ts | 48 +++++++++++++--- test/providers/compliance/s3.test.ts | 58 +++++++++++++++++++ test/providers/quoters/WebhookQuoter.test.ts | 26 +++++++-- 9 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 lib/providers/compliance/index.ts create mode 100644 lib/providers/compliance/mock.ts create mode 100644 lib/providers/compliance/s3.ts create mode 100644 test/providers/compliance/s3.test.ts diff --git a/lib/constants.ts b/lib/constants.ts index c72e9ddb..c9ab46c1 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,3 +1,4 @@ +export const COMPLIANCE_CONFIG_BUCKET = 'compliance-config'; export const WEBHOOK_CONFIG_BUCKET = 'rfq-config'; export const SYNTH_SWITCH_BUCKET = 'synth-config'; export const FADE_RATE_BUCKET = 'fade-rate-config'; @@ -5,6 +6,7 @@ export const INTEGRATION_S3_KEY = 'integration.json'; export const PRODUCTION_S3_KEY = 'production.json'; export const BETA_S3_KEY = 'beta.json'; export const FADE_RATE_S3_KEY = 'fade-rate.json'; +export const PROD_COMPLIANCE_S3_KEY = 'production.json'; export const DYNAMO_TABLE_NAME = { FADES: 'Fades', diff --git a/lib/handlers/quote/injector.ts b/lib/handlers/quote/injector.ts index 33506647..5e146588 100644 --- a/lib/handlers/quote/injector.ts +++ b/lib/handlers/quote/injector.ts @@ -5,9 +5,11 @@ import { default as bunyan, default as Logger } from 'bunyan'; import { BETA_S3_KEY, + COMPLIANCE_CONFIG_BUCKET, FADE_RATE_BUCKET, FADE_RATE_S3_KEY, INTEGRATION_S3_KEY, + PROD_COMPLIANCE_S3_KEY, PRODUCTION_S3_KEY, WEBHOOK_CONFIG_BUCKET, } from '../../constants'; @@ -18,6 +20,7 @@ import { } from '../../entities/aws-metrics-logger'; import { S3WebhookConfigurationProvider } from '../../providers'; import { S3CircuitBreakerConfigurationProvider } from '../../providers/circuit-breaker/s3'; +import { S3FillerComplianceConfigurationProvider } from '../../providers/compliance/s3'; import { Quoter, WebhookQuoter } from '../../quoters'; import { STAGE } from '../../util/stage'; import { ApiInjector, ApiRInj } from '../base/api-handler'; @@ -48,7 +51,14 @@ export class QuoteInjector extends ApiInjector; + getAddrToEndpointsMap(): Promise>>; +} + +export * from './mock'; +export * from './s3'; \ No newline at end of file diff --git a/lib/providers/compliance/mock.ts b/lib/providers/compliance/mock.ts new file mode 100644 index 00000000..8da96de2 --- /dev/null +++ b/lib/providers/compliance/mock.ts @@ -0,0 +1,24 @@ +import { FillerComplianceConfiguration, FillerComplianceConfigurationProvider } from '.'; + +export class MockFillerComplianceConfigurationProvider implements FillerComplianceConfigurationProvider { + constructor(private configs: FillerComplianceConfiguration[]) {} + + async getConfigs(): Promise { + return this.configs; + } + + async getAddrToEndpointsMap(): Promise>> { + const addrToEndpointsMap = new Map>(); + this.configs.forEach((config) => { + config.addresses.forEach((address) => { + if (!addrToEndpointsMap.has(address)) { + addrToEndpointsMap.set(address, new Set()); + } + config.endpoints.forEach((endpoint) => { + addrToEndpointsMap.get(address)?.add(endpoint); + }); + }); + }); + return addrToEndpointsMap; + } +} \ No newline at end of file diff --git a/lib/providers/compliance/s3.ts b/lib/providers/compliance/s3.ts new file mode 100644 index 00000000..e2e438e0 --- /dev/null +++ b/lib/providers/compliance/s3.ts @@ -0,0 +1,60 @@ + +import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'; +import { default as Logger } from 'bunyan'; + +import { checkDefined } from '../../preconditions/preconditions'; +import { FillerComplianceConfiguration, FillerComplianceConfigurationProvider } from '.'; + + +export class S3FillerComplianceConfigurationProvider implements FillerComplianceConfigurationProvider { + private log: Logger; + private configs: FillerComplianceConfiguration[]; + private addrToEndpointsMap: Map>; + + constructor(_log: Logger, private bucket: string, private key: string) { + this.configs = []; + this.log = _log.child({ quoter: 'S3FillerComplianceConfigurationProvider' }); + this.addrToEndpointsMap = new Map>(); + } + + async getAddrToEndpointsMap(): Promise>> { + if (this.configs.length === 0) { + await this.fetchConfigs(); + } + if (this.addrToEndpointsMap.size === 0) { + this.configs.forEach((config) => { + config.addresses.forEach((address) => { + if (!this.addrToEndpointsMap.has(address)) { + this.addrToEndpointsMap.set(address, new Set()); + } + config.endpoints.forEach((endpoint) => { + this.addrToEndpointsMap.get(address)?.add(endpoint); + }); + }); + }) + } + return this.addrToEndpointsMap; + } + + async getConfigs(): Promise { + if ( + this.configs.length === 0 + ) { + await this.fetchConfigs(); + } + return this.configs; + } + + async fetchConfigs(): Promise { + const s3Client = new S3Client({}); + const s3Res = await s3Client.send( + new GetObjectCommand({ + Bucket: this.bucket, + Key: this.key, + }) + ); + const s3Body = checkDefined(s3Res.Body, 's3Res.Body is undefined'); + this.configs = JSON.parse(await s3Body.transformToString()) as FillerComplianceConfiguration[]; + this.log.info({ configsLength: this.configs.map((c) => c.addresses.length) }, `Fetched configs`); + } +} \ No newline at end of file diff --git a/lib/quoters/WebhookQuoter.ts b/lib/quoters/WebhookQuoter.ts index eb7bf5ec..c005ea34 100644 --- a/lib/quoters/WebhookQuoter.ts +++ b/lib/quoters/WebhookQuoter.ts @@ -7,6 +7,7 @@ import { v4 as uuidv4 } from 'uuid'; import { Metric, metricContext, QuoteRequest, QuoteResponse } from '../entities'; import { WebhookConfiguration, WebhookConfigurationProvider } from '../providers'; import { CircuitBreakerConfigurationProvider } from '../providers/circuit-breaker'; +import { FillerComplianceConfigurationProvider } from '../providers/compliance'; import { Quoter, QuoterType } from '.'; // TODO: shorten, maybe take from env config @@ -22,6 +23,7 @@ export class WebhookQuoter implements Quoter { _log: Logger, private webhookProvider: WebhookConfigurationProvider, private circuitBreakerProvider: CircuitBreakerConfigurationProvider, + private complianceProvider: FillerComplianceConfigurationProvider, _allow_list: Set = new Set(['9de8f2376fef4be567f2e242fce750cca347b71853816cbc64f70d568de41ef1']) ) { this.log = _log.child({ quoter: 'WebhookQuoter' }); @@ -30,6 +32,19 @@ export class WebhookQuoter implements Quoter { public async quote(request: QuoteRequest): Promise { const endpoints = await this.getEligibleEndpoints(); + const addrToEndpointsMap = await this.complianceProvider.getAddrToEndpointsMap(); + + endpoints.forEach((endpoint) => { + // remove endpoint if it exists in addrToEndpointsMap.get(request.swapper) + if (addrToEndpointsMap.has(request.swapper)) { + const endpointSet = addrToEndpointsMap.get(request.swapper); + if (endpointSet?.has(endpoint.endpoint)) { + this.log.info({ endpoint: endpoint.endpoint }, `Endpoint is filtered out because of filler's compliance req`); + endpoints.splice(endpoints.indexOf(endpoint), 1); + } + } + }) + this.log.info({ endpoints }, `Fetching quotes from ${endpoints.length} endpoints`); const quotes = await Promise.all(endpoints.map((e) => this.fetchQuote(e, request))); return quotes.filter((q) => q !== null) as QuoteResponse[]; diff --git a/test/handlers/quote/handler.test.ts b/test/handlers/quote/handler.test.ts index 08e46e6b..8a8d621e 100644 --- a/test/handlers/quote/handler.test.ts +++ b/test/handlers/quote/handler.test.ts @@ -15,6 +15,7 @@ import { import { QuoteHandler } from '../../../lib/handlers/quote/handler'; import { MockWebhookConfigurationProvider } from '../../../lib/providers'; import { MockCircuitBreakerConfigurationProvider } from '../../../lib/providers/circuit-breaker/mock'; +import { MockFillerComplianceConfigurationProvider } from '../../../lib/providers/compliance'; import { MOCK_FILLER_ADDRESS, MockQuoter, Quoter, WebhookQuoter } from '../../../lib/quoters'; jest.mock('axios'); @@ -31,6 +32,12 @@ const CHAIN_ID = 1; const logger = Logger.createLogger({ name: 'test' }); logger.level(Logger.FATAL); +const emptyMockComplianceProvider = new MockFillerComplianceConfigurationProvider([]); +const mockComplianceProvider = new MockFillerComplianceConfigurationProvider([{ + endpoints: ['https://uniswap.org', 'google.com'], addresses: [SWAPPER] +}]); + + describe('Quote handler', () => { // Creating mocks for all the handler dependencies. const requestInjectedMock: Promise = new Promise( @@ -212,7 +219,7 @@ describe('Quote handler', () => { const circuitBreakerProvider = new MockCircuitBreakerConfigurationProvider([ { fadeRate: 0.02, enabled: true, hash: '0xuni' }, ]); - const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider)]; + const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider)]; const amountIn = ethers.utils.parseEther('1'); const request = getRequest(amountIn.toString()); @@ -276,7 +283,7 @@ describe('Quote handler', () => { const circuitBreakerProvider = new MockCircuitBreakerConfigurationProvider([ { hash: '0xuni', fadeRate: 0.02, enabled: true }, ]); - const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider)]; + const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider)]; const amountIn = ethers.utils.parseEther('1'); const request = getRequest(amountIn.toString()); @@ -322,7 +329,7 @@ describe('Quote handler', () => { const circuitBreakerProvider = new MockCircuitBreakerConfigurationProvider([ { hash: '0xuni', fadeRate: 0.02, enabled: true }, ]); - const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider)]; + const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider)]; const amountIn = ethers.utils.parseEther('1'); const request = getRequest(amountIn.toString()); @@ -348,7 +355,7 @@ describe('Quote handler', () => { const circuitBreakerProvider = new MockCircuitBreakerConfigurationProvider([ { hash: '0xuni', fadeRate: 0.02, enabled: true }, ]); - const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider)]; + const quoters = [new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider)]; const amountIn = ethers.utils.parseEther('1'); const request = getRequest(amountIn.toString()); @@ -376,7 +383,7 @@ describe('Quote handler', () => { { hash: '0xuni', fadeRate: 0.02, enabled: true }, ]); const quoters = [ - new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider), + new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider), new MockQuoter(logger, 1, 1), ]; const amountIn = ethers.utils.parseEther('1'); @@ -408,7 +415,7 @@ describe('Quote handler', () => { { hash: '0xuni', fadeRate: 0.02, enabled: true }, ]); const quoters = [ - new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider), + new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider), new MockQuoter(logger, 1, 1), ]; const amountIn = ethers.utils.parseEther('1'); @@ -462,7 +469,7 @@ describe('Quote handler', () => { { hash: '0xuni', fadeRate: 0.02, enabled: true }, ]); const quoters = [ - new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider), + new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider), new MockQuoter(logger, 1, 1), ]; const amountIn = ethers.utils.parseEther('1'); @@ -494,5 +501,32 @@ describe('Quote handler', () => { quoteId: expect.any(String), }); }); + + it('respects filler compliance requirements', async () => { + const webhookProvider = new MockWebhookConfigurationProvider([ + { name: 'uniswap', endpoint: 'https://uniswap.org', headers: {}, hash: '0xuni' }, + ]); + const circuitBreakerProvider = new MockCircuitBreakerConfigurationProvider([ + { hash: '0xuni', fadeRate: 0.02, enabled: true }, + ]); + const quoters = [ + new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, mockComplianceProvider), + ]; + const amountIn = ethers.utils.parseEther('1'); + const request = getRequest(amountIn.toString()); + + const response: APIGatewayProxyResult = await getQuoteHandler(quoters).handler( + getEvent(request), + {} as unknown as Context + ); + expect(response.statusCode).toEqual(404); + const quoteResponse: PostQuoteResponse = JSON.parse(response.body); + expect(quoteResponse).toMatchObject( + expect.objectContaining({ + errorCode: 'QUOTE_ERROR', + detail: 'No quotes available', + }) + ) + }) }); }); diff --git a/test/providers/compliance/s3.test.ts b/test/providers/compliance/s3.test.ts new file mode 100644 index 00000000..0e0bbecb --- /dev/null +++ b/test/providers/compliance/s3.test.ts @@ -0,0 +1,58 @@ +import { S3Client } from '@aws-sdk/client-s3'; +import { default as Logger } from 'bunyan'; + +import { FillerComplianceConfiguration,S3FillerComplianceConfigurationProvider } from '../../../lib/providers/compliance'; + +const mockConfigs = [ + { + endpoints: ['https://google.com'], + addresses: ['0x1234'], + }, + { + endpoints: ['https://meta.com'], + addresses: ['0x1234', '0x5678'], + }, +]; + + +function applyMock(configs: FillerComplianceConfiguration[]) { + jest.spyOn(S3Client.prototype, 'send').mockImplementationOnce(() => + Promise.resolve({ + Body: { + transformToString: () => Promise.resolve(JSON.stringify(configs)), + }, + }) + ); +} + + +// silent logger in tests +const logger = Logger.createLogger({ name: 'test' }); +logger.level(Logger.FATAL); + +describe('S3ComplianceConfigurationProvider', () => { + const bucket = 'test-bucket'; + const key = 'test-key'; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('fetches configs', async () => { + applyMock(mockConfigs); + const provider = new S3FillerComplianceConfigurationProvider(logger, bucket, key); + const endpoints = await provider.getConfigs(); + expect(endpoints).toEqual(mockConfigs); + }); + + it('generates addr to endpoints map', async () => { + applyMock(mockConfigs); + const provider = new S3FillerComplianceConfigurationProvider(logger, bucket, key); + expect(await provider.getAddrToEndpointsMap()).toMatchObject( + new Map([ + ['0x1234', new Set(['https://google.com', 'https://meta.com'])], + ['0x5678', new Set(['https://meta.com'])], + ]) + ) + }); +}); \ No newline at end of file diff --git a/test/providers/quoters/WebhookQuoter.test.ts b/test/providers/quoters/WebhookQuoter.test.ts index 8649e5b0..a1b94269 100644 --- a/test/providers/quoters/WebhookQuoter.test.ts +++ b/test/providers/quoters/WebhookQuoter.test.ts @@ -5,6 +5,7 @@ import { BigNumber, ethers } from 'ethers'; import { QuoteRequest } from '../../../lib/entities'; import { MockWebhookConfigurationProvider } from '../../../lib/providers'; import { MockCircuitBreakerConfigurationProvider } from '../../../lib/providers/circuit-breaker/mock'; +import { MockFillerComplianceConfigurationProvider } from '../../../lib/providers/compliance'; import { WebhookQuoter } from '../../../lib/quoters'; jest.mock('axios'); @@ -22,6 +23,11 @@ const WEBHOOK_URL = 'https://uniswap.org'; const WEBHOOK_URL_ONEINCH = 'https://1inch.io'; const WEBHOOK_URL_SEARCHER = 'https://searcher.com'; +const emptyMockComplianceProvider = new MockFillerComplianceConfigurationProvider([]); +const mockComplianceProvider = new MockFillerComplianceConfigurationProvider([{ + endpoints: ['https://uniswap.org', 'google.com'], addresses: [SWAPPER] +}]); + describe('WebhookQuoter tests', () => { afterEach(() => { jest.clearAllMocks(); @@ -38,7 +44,7 @@ describe('WebhookQuoter tests', () => { { hash: '0xsearcher', fadeRate: 0.1, enabled: true }, ]); const logger = { child: () => logger, info: jest.fn(), error: jest.fn(), debug: jest.fn() } as any; - const webhookQuoter = new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider); + const webhookQuoter = new WebhookQuoter(logger, webhookProvider, circuitBreakerProvider, emptyMockComplianceProvider); const request = new QuoteRequest({ tokenInChainId: CHAIN_ID, @@ -83,6 +89,17 @@ describe('WebhookQuoter tests', () => { expect(response.length).toEqual(1); expect(response[0].toResponseJSON()).toEqual({ ...quote, quoteId: expect.any(String) }); }); + + it('Respects filler compliance requirements', async () => { + const webhookQuoter = new WebhookQuoter( + logger, + webhookProvider, + circuitBreakerProvider, + mockComplianceProvider, + ); + + await expect(webhookQuoter.quote(request)).resolves.toStrictEqual([]); + }); // should only call 'uniswap' and 'searcher' given they are enabled in the config it('Only calls to eligible endpoints', async () => { @@ -122,6 +139,7 @@ describe('WebhookQuoter tests', () => { logger, webhookProvider, circuitBreakerProvider, + emptyMockComplianceProvider, new Set(['0x1inch']) ); mockedAxios.post.mockImplementationOnce((_endpoint, _req, _options) => { @@ -157,7 +175,7 @@ describe('WebhookQuoter tests', () => { const cbProvider = new MockCircuitBreakerConfigurationProvider([ { hash: '0xuni', fadeRate: 0.05, enabled: true }, ]); - const quoter = new WebhookQuoter(logger, webhookProvider, cbProvider); + const quoter = new WebhookQuoter(logger, webhookProvider, cbProvider, emptyMockComplianceProvider); await quoter.quote(request); expect(mockedAxios.post).toBeCalledWith( WEBHOOK_URL, @@ -245,7 +263,7 @@ describe('WebhookQuoter tests', () => { const provider = new MockWebhookConfigurationProvider([ { name: 'uniswap', endpoint: WEBHOOK_URL, headers: {}, chainIds: [1], hash: "0xuni" }, ]); - const quoter = new WebhookQuoter(logger, provider, circuitBreakerProvider); + const quoter = new WebhookQuoter(logger, provider, circuitBreakerProvider, emptyMockComplianceProvider); const quote = { amountOut: ethers.utils.parseEther('2').toString(), tokenIn: request.tokenIn, @@ -281,7 +299,7 @@ describe('WebhookQuoter tests', () => { const provider = new MockWebhookConfigurationProvider([ { name: 'uniswap', endpoint: WEBHOOK_URL, headers: {}, chainIds: [4, 5, 6], hash: "0xuni" }, ]); - const quoter = new WebhookQuoter(logger, provider, circuitBreakerProvider); + const quoter = new WebhookQuoter(logger, provider, circuitBreakerProvider, emptyMockComplianceProvider); const response = await quoter.quote(request); From 68b66ecafc8be840e536b65c75390eac5ec22ad5 Mon Sep 17 00:00:00 2001 From: ConjunctiveNormalForm Date: Wed, 8 Nov 2023 11:49:16 -0500 Subject: [PATCH 2/5] newline --- test/providers/compliance/s3.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/providers/compliance/s3.test.ts b/test/providers/compliance/s3.test.ts index 0e0bbecb..770c9ec8 100644 --- a/test/providers/compliance/s3.test.ts +++ b/test/providers/compliance/s3.test.ts @@ -55,4 +55,4 @@ describe('S3ComplianceConfigurationProvider', () => { ]) ) }); -}); \ No newline at end of file +}); From 3a97de80b5f3c45e2df66a8463670237d90f4f56 Mon Sep 17 00:00:00 2001 From: ConjunctiveNormalForm Date: Wed, 8 Nov 2023 13:12:23 -0500 Subject: [PATCH 3/5] address feedbacks --- lib/providers/compliance/index.ts | 3 +- lib/providers/compliance/mock.ts | 21 ++++++------ lib/providers/compliance/s3.ts | 50 +++++++++++++++++++--------- lib/quoters/WebhookQuoter.ts | 28 +++++++++------- test/providers/compliance/s3.test.ts | 20 ++++++++--- 5 files changed, 80 insertions(+), 42 deletions(-) diff --git a/lib/providers/compliance/index.ts b/lib/providers/compliance/index.ts index 4e2d334d..fa71efb3 100644 --- a/lib/providers/compliance/index.ts +++ b/lib/providers/compliance/index.ts @@ -5,7 +5,8 @@ export interface FillerComplianceConfiguration { export interface FillerComplianceConfigurationProvider { getConfigs(): Promise; - getAddrToEndpointsMap(): Promise>>; + // getExcludedAddrToEndpointsMap(): Promise>>; + getEndpointToExcludedAddrsMap(): Promise>>; } export * from './mock'; diff --git a/lib/providers/compliance/mock.ts b/lib/providers/compliance/mock.ts index 8da96de2..4e48d1d7 100644 --- a/lib/providers/compliance/mock.ts +++ b/lib/providers/compliance/mock.ts @@ -6,19 +6,20 @@ export class MockFillerComplianceConfigurationProvider implements FillerComplian async getConfigs(): Promise { return this.configs; } - - async getAddrToEndpointsMap(): Promise>> { - const addrToEndpointsMap = new Map>(); + + async getEndpointToExcludedAddrsMap(): Promise>> { + const map = new Map>(); this.configs.forEach((config) => { - config.addresses.forEach((address) => { - if (!addrToEndpointsMap.has(address)) { - addrToEndpointsMap.set(address, new Set()); + config.endpoints.forEach((endpoint) => { + if (!map.has(endpoint)) { + map.set(endpoint, new Set()); } - config.endpoints.forEach((endpoint) => { - addrToEndpointsMap.get(address)?.add(endpoint); + config.addresses.forEach((address) => { + map.get(endpoint)?.add(address); }); }); - }); - return addrToEndpointsMap; + }) + return map; } + } \ No newline at end of file diff --git a/lib/providers/compliance/s3.ts b/lib/providers/compliance/s3.ts index e2e438e0..e661c2b7 100644 --- a/lib/providers/compliance/s3.ts +++ b/lib/providers/compliance/s3.ts @@ -9,33 +9,53 @@ import { FillerComplianceConfiguration, FillerComplianceConfigurationProvider } export class S3FillerComplianceConfigurationProvider implements FillerComplianceConfigurationProvider { private log: Logger; private configs: FillerComplianceConfiguration[]; - private addrToEndpointsMap: Map>; + private endpointToExcludedAddrsMap: Map>; constructor(_log: Logger, private bucket: string, private key: string) { this.configs = []; this.log = _log.child({ quoter: 'S3FillerComplianceConfigurationProvider' }); - this.addrToEndpointsMap = new Map>(); + this.endpointToExcludedAddrsMap = new Map>(); } - - async getAddrToEndpointsMap(): Promise>> { + async getEndpointToExcludedAddrsMap(): Promise>> { if (this.configs.length === 0) { await this.fetchConfigs(); } - if (this.addrToEndpointsMap.size === 0) { - this.configs.forEach((config) => { + if (this.endpointToExcludedAddrsMap.size > 0) { + return this.endpointToExcludedAddrsMap; + } + this.configs.forEach((config) => { + config.endpoints.forEach((endpoint) => { + if (!this.endpointToExcludedAddrsMap.has(endpoint)) { + this.endpointToExcludedAddrsMap.set(endpoint, new Set()); + } config.addresses.forEach((address) => { - if (!this.addrToEndpointsMap.has(address)) { - this.addrToEndpointsMap.set(address, new Set()); - } - config.endpoints.forEach((endpoint) => { - this.addrToEndpointsMap.get(address)?.add(endpoint); - }); + this.endpointToExcludedAddrsMap.get(endpoint)?.add(address); }); - }) - } - return this.addrToEndpointsMap; + }); + }) + return this.endpointToExcludedAddrsMap; } + // async getExcludedAddrToEndpointsMap(): Promise>> { + // if (this.configs.length === 0) { + // await this.fetchConfigs(); + // } + // if (this.addrToEndpointsMap.size > 0) { + // return this.addrToEndpointsMap; + // } + // this.configs.forEach((config) => { + // config.addresses.forEach((address) => { + // if (!this.addrToEndpointsMap.has(address)) { + // this.addrToEndpointsMap.set(address, new Set()); + // } + // config.endpoints.forEach((endpoint) => { + // this.addrToEndpointsMap.get(address)?.add(endpoint); + // }); + // }); + // }) + // return this.addrToEndpointsMap; + // } + async getConfigs(): Promise { if ( this.configs.length === 0 diff --git a/lib/quoters/WebhookQuoter.ts b/lib/quoters/WebhookQuoter.ts index c005ea34..06a9196b 100644 --- a/lib/quoters/WebhookQuoter.ts +++ b/lib/quoters/WebhookQuoter.ts @@ -32,18 +32,22 @@ export class WebhookQuoter implements Quoter { public async quote(request: QuoteRequest): Promise { const endpoints = await this.getEligibleEndpoints(); - const addrToEndpointsMap = await this.complianceProvider.getAddrToEndpointsMap(); - - endpoints.forEach((endpoint) => { - // remove endpoint if it exists in addrToEndpointsMap.get(request.swapper) - if (addrToEndpointsMap.has(request.swapper)) { - const endpointSet = addrToEndpointsMap.get(request.swapper); - if (endpointSet?.has(endpoint.endpoint)) { - this.log.info({ endpoint: endpoint.endpoint }, `Endpoint is filtered out because of filler's compliance req`); - endpoints.splice(endpoints.indexOf(endpoint), 1); - } - } - }) + //const addrToEndpointsMap = await this.complianceProvider.getExcludedAddrToEndpointsMap(); + const endpointToAddrsMap = await this.complianceProvider.getEndpointToExcludedAddrsMap(); + endpoints.filter((e) => { + return endpointToAddrsMap.get(e.endpoint) === undefined || + !endpointToAddrsMap.get(e.endpoint)?.has(request.swapper); + }); + // endpoints.forEach((endpoint) => { + // // remove endpoint if it exists in addrToEndpointsMap.get(request.swapper) + // if (addrToEndpointsMap.has(request.swapper)) { + // const endpointSet = addrToEndpointsMap.get(request.swapper); + // if (endpointSet?.has(endpoint.endpoint)) { + // this.log.info({ endpoint: endpoint.endpoint }, `Endpoint is filtered out because of filler's compliance req`); + // endpoints.splice(endpoints.indexOf(endpoint), 1); + // } + // } + // }) this.log.info({ endpoints }, `Fetching quotes from ${endpoints.length} endpoints`); const quotes = await Promise.all(endpoints.map((e) => this.fetchQuote(e, request))); diff --git a/test/providers/compliance/s3.test.ts b/test/providers/compliance/s3.test.ts index 770c9ec8..9067b96d 100644 --- a/test/providers/compliance/s3.test.ts +++ b/test/providers/compliance/s3.test.ts @@ -45,13 +45,25 @@ describe('S3ComplianceConfigurationProvider', () => { expect(endpoints).toEqual(mockConfigs); }); - it('generates addr to endpoints map', async () => { + // it('generates addr to endpoints map', async () => { + // applyMock(mockConfigs); + // const provider = new S3FillerComplianceConfigurationProvider(logger, bucket, key); + // expect(await provider.getExcludedAddrToEndpointsMap()).toMatchObject( + // new Map([ + // ['0x1234', new Set(['https://google.com', 'https://meta.com'])], + // ['0x5678', new Set(['https://meta.com'])], + // ]) + // ) + // }); + + it('generates endpoint to addrs map', async () => { applyMock(mockConfigs); const provider = new S3FillerComplianceConfigurationProvider(logger, bucket, key); - expect(await provider.getAddrToEndpointsMap()).toMatchObject( + const map = await provider.getEndpointToExcludedAddrsMap(); + expect(map).toMatchObject( new Map([ - ['0x1234', new Set(['https://google.com', 'https://meta.com'])], - ['0x5678', new Set(['https://meta.com'])], + ['https://google.com', new Set(['0x1234'])], + ['https://meta.com', new Set(['0x1234', '0x5678'])], ]) ) }); From 9f758bc25eb29e15acb8d1cdc5b29c63fb81456c Mon Sep 17 00:00:00 2001 From: ConjunctiveNormalForm Date: Wed, 8 Nov 2023 13:12:54 -0500 Subject: [PATCH 4/5] remove old code --- lib/providers/compliance/s3.ts | 20 -------------------- lib/quoters/WebhookQuoter.ts | 10 ---------- test/providers/compliance/s3.test.ts | 11 ----------- 3 files changed, 41 deletions(-) diff --git a/lib/providers/compliance/s3.ts b/lib/providers/compliance/s3.ts index e661c2b7..f5248f5d 100644 --- a/lib/providers/compliance/s3.ts +++ b/lib/providers/compliance/s3.ts @@ -36,26 +36,6 @@ export class S3FillerComplianceConfigurationProvider implements FillerCompliance return this.endpointToExcludedAddrsMap; } - // async getExcludedAddrToEndpointsMap(): Promise>> { - // if (this.configs.length === 0) { - // await this.fetchConfigs(); - // } - // if (this.addrToEndpointsMap.size > 0) { - // return this.addrToEndpointsMap; - // } - // this.configs.forEach((config) => { - // config.addresses.forEach((address) => { - // if (!this.addrToEndpointsMap.has(address)) { - // this.addrToEndpointsMap.set(address, new Set()); - // } - // config.endpoints.forEach((endpoint) => { - // this.addrToEndpointsMap.get(address)?.add(endpoint); - // }); - // }); - // }) - // return this.addrToEndpointsMap; - // } - async getConfigs(): Promise { if ( this.configs.length === 0 diff --git a/lib/quoters/WebhookQuoter.ts b/lib/quoters/WebhookQuoter.ts index 06a9196b..4bbcb737 100644 --- a/lib/quoters/WebhookQuoter.ts +++ b/lib/quoters/WebhookQuoter.ts @@ -38,16 +38,6 @@ export class WebhookQuoter implements Quoter { return endpointToAddrsMap.get(e.endpoint) === undefined || !endpointToAddrsMap.get(e.endpoint)?.has(request.swapper); }); - // endpoints.forEach((endpoint) => { - // // remove endpoint if it exists in addrToEndpointsMap.get(request.swapper) - // if (addrToEndpointsMap.has(request.swapper)) { - // const endpointSet = addrToEndpointsMap.get(request.swapper); - // if (endpointSet?.has(endpoint.endpoint)) { - // this.log.info({ endpoint: endpoint.endpoint }, `Endpoint is filtered out because of filler's compliance req`); - // endpoints.splice(endpoints.indexOf(endpoint), 1); - // } - // } - // }) this.log.info({ endpoints }, `Fetching quotes from ${endpoints.length} endpoints`); const quotes = await Promise.all(endpoints.map((e) => this.fetchQuote(e, request))); diff --git a/test/providers/compliance/s3.test.ts b/test/providers/compliance/s3.test.ts index 9067b96d..0fe689cd 100644 --- a/test/providers/compliance/s3.test.ts +++ b/test/providers/compliance/s3.test.ts @@ -45,17 +45,6 @@ describe('S3ComplianceConfigurationProvider', () => { expect(endpoints).toEqual(mockConfigs); }); - // it('generates addr to endpoints map', async () => { - // applyMock(mockConfigs); - // const provider = new S3FillerComplianceConfigurationProvider(logger, bucket, key); - // expect(await provider.getExcludedAddrToEndpointsMap()).toMatchObject( - // new Map([ - // ['0x1234', new Set(['https://google.com', 'https://meta.com'])], - // ['0x5678', new Set(['https://meta.com'])], - // ]) - // ) - // }); - it('generates endpoint to addrs map', async () => { applyMock(mockConfigs); const provider = new S3FillerComplianceConfigurationProvider(logger, bucket, key); From a3370e0a58fcacde5ee8bc6c14f80f9937b062c0 Mon Sep 17 00:00:00 2001 From: ConjunctiveNormalForm Date: Wed, 8 Nov 2023 13:14:25 -0500 Subject: [PATCH 5/5] remove old comment --- lib/quoters/WebhookQuoter.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/quoters/WebhookQuoter.ts b/lib/quoters/WebhookQuoter.ts index 4bbcb737..3dbffdee 100644 --- a/lib/quoters/WebhookQuoter.ts +++ b/lib/quoters/WebhookQuoter.ts @@ -32,7 +32,6 @@ export class WebhookQuoter implements Quoter { public async quote(request: QuoteRequest): Promise { const endpoints = await this.getEligibleEndpoints(); - //const addrToEndpointsMap = await this.complianceProvider.getExcludedAddrToEndpointsMap(); const endpointToAddrsMap = await this.complianceProvider.getEndpointToExcludedAddrsMap(); endpoints.filter((e) => { return endpointToAddrsMap.get(e.endpoint) === undefined ||