fix: Exclusive API keys for select integrations (#317)
* Initial commit of changes * Added unit tests for filtering process * linting * Update packages/asset-swapper/src/utils/quote_requestor.ts Co-authored-by: phil-ociraptor <philipliao@gmail.com> * lint and refactor based on feedback Co-authored-by: phil-ociraptor <philipliao@gmail.com>
This commit is contained in:
parent
7439871aa0
commit
e838a6801b
@ -244,6 +244,7 @@ export interface RfqRequestOpts {
|
|||||||
takerAddress: string;
|
takerAddress: string;
|
||||||
txOrigin: string;
|
txOrigin: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
|
apiKeyWhitelist?: string[];
|
||||||
intentOnFilling: boolean;
|
intentOnFilling: boolean;
|
||||||
isIndicative?: boolean;
|
isIndicative?: boolean;
|
||||||
makerEndpointMaxResponseTimeMs?: number;
|
makerEndpointMaxResponseTimeMs?: number;
|
||||||
|
@ -178,6 +178,42 @@ export class QuoteRequestor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets both standard RFQ makers and "alternative" RFQ makers and combines them together
|
||||||
|
* in a single configuration map. If an integration key whitelist is present, it will be used
|
||||||
|
* to filter a specific makers.
|
||||||
|
*
|
||||||
|
* @param options the RfqmRequestOptions passed in
|
||||||
|
* @param assetOfferings the RFQM or RFQT maker offerings
|
||||||
|
* @returns a list of TypedMakerUrl instances
|
||||||
|
*/
|
||||||
|
public static getTypedMakerUrlsAndWhitelist(
|
||||||
|
options: Pick<RfqmRequestOptions, 'apiKeyWhitelist' | 'altRfqAssetOfferings'>,
|
||||||
|
assetOfferings: RfqMakerAssetOfferings,
|
||||||
|
): TypedMakerUrl[] {
|
||||||
|
const standardUrls = Object.keys(assetOfferings).map(
|
||||||
|
(mm: string): TypedMakerUrl => {
|
||||||
|
return { pairType: RfqPairType.Standard, url: mm };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const altUrls = options.altRfqAssetOfferings
|
||||||
|
? Object.keys(options.altRfqAssetOfferings).map(
|
||||||
|
(mm: string): TypedMakerUrl => {
|
||||||
|
return { pairType: RfqPairType.Alt, url: mm };
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
let typedMakerUrls = standardUrls.concat(altUrls);
|
||||||
|
|
||||||
|
// If there is a whitelist, only allow approved maker URLs
|
||||||
|
if (options.apiKeyWhitelist !== undefined) {
|
||||||
|
const whitelist = new Set(options.apiKeyWhitelist.map(key => key.toLowerCase()));
|
||||||
|
typedMakerUrls = typedMakerUrls.filter(makerUrl => whitelist.has(makerUrl.url.toLowerCase()));
|
||||||
|
}
|
||||||
|
return typedMakerUrls;
|
||||||
|
}
|
||||||
|
|
||||||
public static getDurationUntilExpirationMs(expirationTimeSeconds: BigNumber): BigNumber {
|
public static getDurationUntilExpirationMs(expirationTimeSeconds: BigNumber): BigNumber {
|
||||||
const expirationTimeMs = expirationTimeSeconds.times(constants.ONE_SECOND_MS);
|
const expirationTimeMs = expirationTimeSeconds.times(constants.ONE_SECOND_MS);
|
||||||
const currentTimeMs = new BigNumber(Date.now());
|
const currentTimeMs = new BigNumber(Date.now());
|
||||||
@ -401,21 +437,6 @@ export class QuoteRequestor {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const standardUrls = Object.keys(assetOfferings).map(
|
|
||||||
(mm: string): TypedMakerUrl => {
|
|
||||||
return { pairType: RfqPairType.Standard, url: mm };
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const altUrls = options.altRfqAssetOfferings
|
|
||||||
? Object.keys(options.altRfqAssetOfferings).map(
|
|
||||||
(mm: string): TypedMakerUrl => {
|
|
||||||
return { pairType: RfqPairType.Alt, url: mm };
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const typedMakerUrls = standardUrls.concat(altUrls);
|
|
||||||
|
|
||||||
const timeoutMs =
|
const timeoutMs =
|
||||||
options.makerEndpointMaxResponseTimeMs ||
|
options.makerEndpointMaxResponseTimeMs ||
|
||||||
constants.DEFAULT_RFQT_REQUEST_OPTS.makerEndpointMaxResponseTimeMs!;
|
constants.DEFAULT_RFQT_REQUEST_OPTS.makerEndpointMaxResponseTimeMs!;
|
||||||
@ -427,6 +448,7 @@ export class QuoteRequestor {
|
|||||||
cancelTokenSource.cancel('timeout via cancel token');
|
cancelTokenSource.cancel('timeout via cancel token');
|
||||||
}, timeoutMs + bufferMs);
|
}, timeoutMs + bufferMs);
|
||||||
|
|
||||||
|
const typedMakerUrls = QuoteRequestor.getTypedMakerUrlsAndWhitelist(options, assetOfferings);
|
||||||
const quotePromises = typedMakerUrls.map(async typedMakerUrl => {
|
const quotePromises = typedMakerUrls.map(async typedMakerUrl => {
|
||||||
// filter out requests to skip
|
// filter out requests to skip
|
||||||
const isBlacklisted = rfqMakerBlacklist.isMakerBlacklisted(typedMakerUrl.url);
|
const isBlacklisted = rfqMakerBlacklist.isMakerBlacklisted(typedMakerUrl.url);
|
||||||
|
@ -834,6 +834,39 @@ describe('QuoteRequestor', async () => {
|
|||||||
quoteRequestorHttpClient,
|
quoteRequestorHttpClient,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should be able to handle and filter RFQ offerings', () => {
|
||||||
|
const tests: Array<[string[] | undefined, string[]]> = [
|
||||||
|
[['https://top.maker'], []],
|
||||||
|
[undefined, ['https://foo.bar/', 'https://lorem.ipsum/']],
|
||||||
|
[['https://lorem.ipsum/'], ['https://lorem.ipsum/']],
|
||||||
|
];
|
||||||
|
for (const test of tests) {
|
||||||
|
const [apiKeyWhitelist, results] = test;
|
||||||
|
const response = QuoteRequestor.getTypedMakerUrlsAndWhitelist(
|
||||||
|
{
|
||||||
|
apiKeyWhitelist,
|
||||||
|
altRfqAssetOfferings: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'https://foo.bar/': [
|
||||||
|
[
|
||||||
|
'0xA6cD4cb8c62aCDe44739E3Ed0F1d13E0e31f2d94',
|
||||||
|
'0xF45107c0200a04A8aB9C600cc52A3C89AE5D0489',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'https://lorem.ipsum/': [
|
||||||
|
[
|
||||||
|
'0xA6cD4cb8c62aCDe44739E3Ed0F1d13E0e31f2d94',
|
||||||
|
'0xF45107c0200a04A8aB9C600cc52A3C89AE5D0489',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const typedUrls = response.map(typed => typed.url);
|
||||||
|
expect(typedUrls).to.eql(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should return successful alt indicative quotes', async () => {
|
it('should return successful alt indicative quotes', async () => {
|
||||||
const takerAddress = '0xd209925defc99488e3afff1174e48b4fa628302a';
|
const takerAddress = '0xd209925defc99488e3afff1174e48b4fa628302a';
|
||||||
const txOrigin = '0xf209925defc99488e3afff1174e48b4fa628302a';
|
const txOrigin = '0xf209925defc99488e3afff1174e48b4fa628302a';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user