feat: add proxy configuration to axios instance in RFQT asset-swapper (#159)

* add proxy configuration to axios instance

* add support for additional axios instance opts

* move quoteRequestorHttpClient parameter

* fix tests, build errors

* prettier

* bump axios

* bumped mock-axios-adapter version

* downgrade axios again

* re-upgrade axios 🤦

* updated yarn.lock

* updated changelog

Co-authored-by: Alex Kroeger <alexrkroeger@gmail.com>
This commit is contained in:
Oskar Paolini 2021-03-03 20:38:54 +01:00 committed by GitHub
parent db3e076d03
commit f3ca4293bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 43 deletions

View File

@ -5,6 +5,10 @@
{ {
"note": "Add MooniswapLiquidityProvider \"direct\" route to EP consumer.", "note": "Add MooniswapLiquidityProvider \"direct\" route to EP consumer.",
"pr": 143 "pr": 143
},
{
"note": "Enable the ability to send RFQT requests thru a proxy",
"pr": 159
} }
] ]
}, },

View File

@ -75,8 +75,8 @@
"@ethersproject/address": "^5.0.1", "@ethersproject/address": "^5.0.1",
"@ethersproject/contracts": "^5.0.1", "@ethersproject/contracts": "^5.0.1",
"@ethersproject/providers": "^5.0.4", "@ethersproject/providers": "^5.0.4",
"axios": "^0.19.2", "axios": "^0.21.1",
"axios-mock-adapter": "^1.18.1", "axios-mock-adapter": "^1.19.0",
"cream-sor": "^0.3.3", "cream-sor": "^0.3.3",
"decimal.js": "^10.2.0", "decimal.js": "^10.2.0",
"ethereum-types": "^3.4.0", "ethereum-types": "^3.4.0",

View File

@ -94,6 +94,9 @@ export { DEFAULT_FEE_SCHEDULE, DEFAULT_GAS_SCHEDULE } from './utils/market_opera
export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000); export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000);
// tslint:disable-next-line: custom-no-magic-numbers
export const KEEP_ALIVE_TTL = 5 * 60 * ONE_SECOND_MS;
export const constants = { export const constants = {
ETH_GAS_STATION_API_URL, ETH_GAS_STATION_API_URL,
PROTOCOL_FEE_MULTIPLIER, PROTOCOL_FEE_MULTIPLIER,

View File

@ -1,11 +1,14 @@
import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { FillQuoteTransformerOrderType, LimitOrder } from '@0x/protocol-utils'; import { FillQuoteTransformerOrderType, LimitOrder } from '@0x/protocol-utils';
import { BigNumber, providerUtils } from '@0x/utils'; import { BigNumber, providerUtils } from '@0x/utils';
import Axios, { AxiosInstance } from 'axios';
import { BlockParamLiteral, SupportedProvider, ZeroExProvider } from 'ethereum-types'; import { BlockParamLiteral, SupportedProvider, ZeroExProvider } from 'ethereum-types';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { artifacts } from './artifacts'; import { artifacts } from './artifacts';
import { constants, INVALID_SIGNATURE } from './constants'; import { constants, INVALID_SIGNATURE, KEEP_ALIVE_TTL } from './constants';
import { import {
AssetSwapperContractAddresses, AssetSwapperContractAddresses,
MarketBuySwapQuote, MarketBuySwapQuote,
@ -70,6 +73,7 @@ export class SwapQuoter {
private readonly _protocolFeeUtils: ProtocolFeeUtils; private readonly _protocolFeeUtils: ProtocolFeeUtils;
private readonly _marketOperationUtils: MarketOperationUtils; private readonly _marketOperationUtils: MarketOperationUtils;
private readonly _rfqtOptions?: SwapQuoterRfqtOpts; private readonly _rfqtOptions?: SwapQuoterRfqtOpts;
private readonly _quoteRequestorHttpClient: AxiosInstance;
/** /**
* Instantiates a new SwapQuoter instance * Instantiates a new SwapQuoter instance
@ -144,6 +148,12 @@ export class SwapQuoter {
exchangeAddress: this._contractAddresses.exchange, exchangeAddress: this._contractAddresses.exchange,
}, },
); );
this._quoteRequestorHttpClient = Axios.create({
httpAgent: new HttpAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
httpsAgent: new HttpsAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
...(rfqt ? rfqt.axiosInstanceOpts : {}),
});
} }
public async getBatchMarketBuySwapQuoteAsync( public async getBatchMarketBuySwapQuoteAsync(
@ -348,6 +358,7 @@ export class SwapQuoter {
if (calcOpts.rfqt !== undefined) { if (calcOpts.rfqt !== undefined) {
calcOpts.rfqt.quoteRequestor = new QuoteRequestor( calcOpts.rfqt.quoteRequestor = new QuoteRequestor(
rfqtOptions ? rfqtOptions.makerAssetOfferings || {} : {}, rfqtOptions ? rfqtOptions.makerAssetOfferings || {} : {},
this._quoteRequestorHttpClient,
rfqtOptions ? rfqtOptions.altRfqCreds : undefined, rfqtOptions ? rfqtOptions.altRfqCreds : undefined,
rfqtOptions ? rfqtOptions.warningLogger : undefined, rfqtOptions ? rfqtOptions.warningLogger : undefined,
rfqtOptions ? rfqtOptions.infoLogger : undefined, rfqtOptions ? rfqtOptions.infoLogger : undefined,

View File

@ -9,6 +9,7 @@ import {
} from '@0x/protocol-utils'; } from '@0x/protocol-utils';
import { TakerRequestQueryParams, V4SignedRfqOrder } from '@0x/quote-server'; import { TakerRequestQueryParams, V4SignedRfqOrder } from '@0x/quote-server';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { AxiosRequestConfig } from 'axios';
import { import {
ERC20BridgeSource, ERC20BridgeSource,
@ -291,6 +292,7 @@ export interface SwapQuoterRfqtOpts {
}; };
warningLogger?: LogFunction; warningLogger?: LogFunction;
infoLogger?: LogFunction; infoLogger?: LogFunction;
axiosInstanceOpts?: AxiosRequestConfig;
} }
export type AssetSwapperContractAddresses = ContractAddresses; export type AssetSwapperContractAddresses = ContractAddresses;

View File

@ -2,9 +2,7 @@ import { schemas, SchemaValidator } from '@0x/json-schemas';
import { FillQuoteTransformerOrderType, Signature } from '@0x/protocol-utils'; import { FillQuoteTransformerOrderType, Signature } from '@0x/protocol-utils';
import { TakerRequestQueryParams, V4RFQFirmQuote, V4RFQIndicativeQuote, V4SignedRfqOrder } from '@0x/quote-server'; import { TakerRequestQueryParams, V4RFQFirmQuote, V4RFQIndicativeQuote, V4SignedRfqOrder } from '@0x/quote-server';
import { BigNumber, NULL_ADDRESS } from '@0x/utils'; import { BigNumber, NULL_ADDRESS } from '@0x/utils';
import Axios, { AxiosInstance } from 'axios'; import { AxiosInstance } from 'axios';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';
import { constants } from '../constants'; import { constants } from '../constants';
import { import {
@ -20,17 +18,8 @@ import {
} from '../types'; } from '../types';
import { returnQuoteFromAltMMAsync } from './alt_mm_implementation_utils'; import { returnQuoteFromAltMMAsync } from './alt_mm_implementation_utils';
import { ONE_SECOND_MS } from './market_operation_utils/constants';
import { RfqMakerBlacklist } from './rfq_maker_blacklist'; import { RfqMakerBlacklist } from './rfq_maker_blacklist';
// tslint:disable-next-line: custom-no-magic-numbers
const KEEP_ALIVE_TTL = 5 * 60 * ONE_SECOND_MS;
export const quoteRequestorHttpClient: AxiosInstance = Axios.create({
httpAgent: new HttpAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
httpsAgent: new HttpsAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
});
const MAKER_TIMEOUT_STREAK_LENGTH = 10; const MAKER_TIMEOUT_STREAK_LENGTH = 10;
const MAKER_TIMEOUT_BLACKLIST_DURATION_MINUTES = 10; const MAKER_TIMEOUT_BLACKLIST_DURATION_MINUTES = 10;
const rfqMakerBlacklist = new RfqMakerBlacklist(MAKER_TIMEOUT_STREAK_LENGTH, MAKER_TIMEOUT_BLACKLIST_DURATION_MINUTES); const rfqMakerBlacklist = new RfqMakerBlacklist(MAKER_TIMEOUT_STREAK_LENGTH, MAKER_TIMEOUT_BLACKLIST_DURATION_MINUTES);
@ -137,6 +126,7 @@ export class QuoteRequestor {
constructor( constructor(
private readonly _rfqtAssetOfferings: RfqtMakerAssetOfferings, private readonly _rfqtAssetOfferings: RfqtMakerAssetOfferings,
private readonly _quoteRequestorHttpClient: AxiosInstance,
private readonly _altRfqCreds?: { altRfqApiKey: string; altRfqProfile: string }, private readonly _altRfqCreds?: { altRfqApiKey: string; altRfqProfile: string },
private readonly _warningLogger: LogFunction = constants.DEFAULT_WARNING_LOGGER, private readonly _warningLogger: LogFunction = constants.DEFAULT_WARNING_LOGGER,
private readonly _infoLogger: LogFunction = constants.DEFAULT_INFO_LOGGER, private readonly _infoLogger: LogFunction = constants.DEFAULT_INFO_LOGGER,
@ -420,7 +410,7 @@ export class QuoteRequestor {
: options.makerEndpointMaxResponseTimeMs; : options.makerEndpointMaxResponseTimeMs;
try { try {
if (typedMakerUrl.pairType === RfqPairType.Standard) { if (typedMakerUrl.pairType === RfqPairType.Standard) {
const response = await quoteRequestorHttpClient.get(`${typedMakerUrl.url}/${quotePath}`, { const response = await this._quoteRequestorHttpClient.get(`${typedMakerUrl.url}/${quotePath}`, {
headers: { '0x-api-key': options.apiKey }, headers: { '0x-api-key': options.apiKey },
params: requestParams, params: requestParams,
timeout: maxResponseTimeMs, timeout: maxResponseTimeMs,
@ -456,7 +446,7 @@ export class QuoteRequestor {
maxResponseTimeMs, maxResponseTimeMs,
options.altRfqtAssetOfferings || {}, options.altRfqtAssetOfferings || {},
requestParams, requestParams,
quoteRequestorHttpClient, this._quoteRequestorHttpClient,
); );
const latencyMs = Date.now() - timeBeforeAwait; const latencyMs = Date.now() - timeBeforeAwait;

View File

@ -3,11 +3,14 @@ import { FillQuoteTransformerOrderType, SignatureType } from '@0x/protocol-utils
import { TakerRequestQueryParams, V4RFQIndicativeQuote } from '@0x/quote-server'; import { TakerRequestQueryParams, V4RFQIndicativeQuote } from '@0x/quote-server';
import { StatusCodes } from '@0x/types'; import { StatusCodes } from '@0x/types';
import { BigNumber, logUtils } from '@0x/utils'; import { BigNumber, logUtils } from '@0x/utils';
import Axios, { AxiosInstance } from 'axios';
import * as chai from 'chai'; import * as chai from 'chai';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';
import _ = require('lodash'); import _ = require('lodash');
import 'mocha'; import 'mocha';
import { constants } from '../src/constants'; import { constants, KEEP_ALIVE_TTL } from '../src/constants';
import { import {
AltMockedRfqtQuoteResponse, AltMockedRfqtQuoteResponse,
AltQuoteModel, AltQuoteModel,
@ -18,11 +21,16 @@ import {
MockedRfqtQuoteResponse, MockedRfqtQuoteResponse,
} from '../src/types'; } from '../src/types';
import { NULL_ADDRESS } from '../src/utils/market_operation_utils/constants'; import { NULL_ADDRESS } from '../src/utils/market_operation_utils/constants';
import { QuoteRequestor, quoteRequestorHttpClient } from '../src/utils/quote_requestor'; import { QuoteRequestor } from '../src/utils/quote_requestor';
import { chaiSetup } from './utils/chai_setup'; import { chaiSetup } from './utils/chai_setup';
import { RfqtQuoteEndpoint, testHelpers } from './utils/test_helpers'; import { RfqtQuoteEndpoint, testHelpers } from './utils/test_helpers';
const quoteRequestorHttpClient = Axios.create({
httpAgent: new HttpAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
httpsAgent: new HttpsAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
});
chaiSetup.configure(); chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
const ALT_MM_API_KEY = 'averysecurekey'; const ALT_MM_API_KEY = 'averysecurekey';
@ -215,6 +223,7 @@ describe('QuoteRequestor', async () => {
'https://426.0.0.1': [] /* Shouldn't ping an RFQ-T provider when they don't support the requested asset pair. */, 'https://426.0.0.1': [] /* Shouldn't ping an RFQ-T provider when they don't support the requested asset pair. */,
'https://37.0.0.1': [[makerToken, takerToken]], 'https://37.0.0.1': [[makerToken, takerToken]],
}, },
quoteRequestorHttpClient,
ALT_RFQ_CREDS, ALT_RFQ_CREDS,
); );
const resp = await qr.requestRfqtFirmQuotesAsync( const resp = await qr.requestRfqtFirmQuotesAsync(
@ -327,15 +336,18 @@ describe('QuoteRequestor', async () => {
[], [],
RfqtQuoteEndpoint.Indicative, RfqtQuoteEndpoint.Indicative,
async () => { async () => {
const qr = new QuoteRequestor({ const qr = new QuoteRequestor(
'https://1337.0.0.1': [[makerToken, takerToken]], {
'https://420.0.0.1': [[makerToken, takerToken]], 'https://1337.0.0.1': [[makerToken, takerToken]],
'https://421.0.0.1': [[makerToken, takerToken]], 'https://420.0.0.1': [[makerToken, takerToken]],
'https://422.0.0.1': [[makerToken, takerToken]], 'https://421.0.0.1': [[makerToken, takerToken]],
'https://423.0.0.1': [[makerToken, takerToken]], 'https://422.0.0.1': [[makerToken, takerToken]],
'https://424.0.0.1': [[makerToken, takerToken]], 'https://423.0.0.1': [[makerToken, takerToken]],
'https://37.0.0.1': [[makerToken, takerToken]], 'https://424.0.0.1': [[makerToken, takerToken]],
}); 'https://37.0.0.1': [[makerToken, takerToken]],
},
quoteRequestorHttpClient,
);
const resp = await qr.requestRfqtIndicativeQuotesAsync( const resp = await qr.requestRfqtIndicativeQuotesAsync(
makerToken, makerToken,
takerToken, takerToken,
@ -391,7 +403,10 @@ describe('QuoteRequestor', async () => {
[], [],
RfqtQuoteEndpoint.Indicative, RfqtQuoteEndpoint.Indicative,
async () => { async () => {
const qr = new QuoteRequestor({ 'https://1337.0.0.1': [[makerToken, takerToken]] }); const qr = new QuoteRequestor(
{ 'https://1337.0.0.1': [[makerToken, takerToken]] },
quoteRequestorHttpClient,
);
const resp = await qr.requestRfqtIndicativeQuotesAsync( const resp = await qr.requestRfqtIndicativeQuotesAsync(
makerToken, makerToken,
takerToken, takerToken,
@ -623,7 +638,7 @@ describe('QuoteRequestor', async () => {
altMockedRequests, altMockedRequests,
RfqtQuoteEndpoint.Indicative, RfqtQuoteEndpoint.Indicative,
async () => { async () => {
const qr = new QuoteRequestor({}, ALT_RFQ_CREDS); const qr = new QuoteRequestor({}, quoteRequestorHttpClient, ALT_RFQ_CREDS);
const resp = await qr.requestRfqtIndicativeQuotesAsync( const resp = await qr.requestRfqtIndicativeQuotesAsync(
altScenario.requestedMakerToken, altScenario.requestedMakerToken,
altScenario.requestedTakerToken, altScenario.requestedTakerToken,

View File

@ -2991,18 +2991,20 @@ aws4@^1.8.0:
version "1.10.1" version "1.10.1"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
axios-mock-adapter@^1.18.1: axios-mock-adapter@^1.19.0:
version "1.19.0" version "1.19.0"
resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz#9d72e321a6c5418e1eff067aa99761a86c5188a4" resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz#9d72e321a6c5418e1eff067aa99761a86c5188a4"
integrity sha512-D+0U4LNPr7WroiBDvWilzTMYPYTuZlbo6BI8YHZtj7wYQS8NkARlP9KBt8IWWHTQJ0q/8oZ0ClPBtKCCkx8cQg==
dependencies: dependencies:
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
is-buffer "^2.0.3" is-buffer "^2.0.3"
axios@^0.19.2: axios@^0.21.1:
version "0.19.2" version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies: dependencies:
follow-redirects "1.5.10" follow-redirects "^1.10.0"
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0" version "6.26.0"
@ -4757,7 +4759,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@3.1.0, debug@=3.1.0: debug@3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies: dependencies:
@ -6353,11 +6355,10 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
inherits "^2.0.3" inherits "^2.0.3"
readable-stream "^2.3.6" readable-stream "^2.3.6"
follow-redirects@1.5.10: follow-redirects@^1.10.0:
version "1.5.10" version "1.13.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
dependencies: integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
debug "=3.1.0"
for-each@~0.3.3: for-each@~0.3.3:
version "0.3.3" version "0.3.3"
@ -10315,9 +10316,9 @@ public-encrypt@^4.0.0:
randombytes "^2.0.1" randombytes "^2.0.1"
safe-buffer "^5.1.2" safe-buffer "^5.1.2"
"publish-release@git+https://github.com/0xProject/publish-release.git#3f8be1105a356527f4b362ff456d94bf9a82f2ed": "publish-release@https://github.com/0xProject/publish-release.git#3f8be1105a356527f4b362ff456d94bf9a82f2ed":
version "1.3.3" version "1.3.3"
resolved "git+https://github.com/0xProject/publish-release.git#3f8be1105a356527f4b362ff456d94bf9a82f2ed" resolved "https://github.com/0xProject/publish-release.git#3f8be1105a356527f4b362ff456d94bf9a82f2ed"
dependencies: dependencies:
async "^0.9.0" async "^0.9.0"
ghauth "^2.0.0" ghauth "^2.0.0"