From 281e6acca59637bada2dfc62542842f5a6efe901 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 30 Nov 2021 09:06:05 +1000 Subject: [PATCH] chore: Add ability to capture sampler metrics (#374) * chore: Add ability to capture sampler metrics * Added block number metrics --- packages/asset-swapper/CHANGELOG.json | 9 ++++++ .../contracts/src/UtilitySampler.sol | 15 +++++++++ packages/asset-swapper/src/index.ts | 1 + packages/asset-swapper/src/types.ts | 1 + .../src/utils/market_operation_utils/index.ts | 10 ++++++ .../utils/market_operation_utils/sampler.ts | 31 +++++++++++++++++++ .../sampler_operations.ts | 24 ++++++++++++++ .../src/utils/market_operation_utils/types.ts | 22 +++++++++++++ .../test/market_operation_utils_test.ts | 3 ++ 9 files changed, 116 insertions(+) diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index d763024ea1..e1020e000e 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "16.38.0", + "changes": [ + { + "note": "Capture sampler metrics", + "pr": 374 + } + ] + }, { "version": "16.37.0", "changes": [ diff --git a/packages/asset-swapper/contracts/src/UtilitySampler.sol b/packages/asset-swapper/contracts/src/UtilitySampler.sol index 4e5abd9098..bbc3c5a1ad 100644 --- a/packages/asset-swapper/contracts/src/UtilitySampler.sol +++ b/packages/asset-swapper/contracts/src/UtilitySampler.sol @@ -77,4 +77,19 @@ contract UtilitySampler { assembly { size := extcodesize(account) } return size > 0; } + + function getGasLeft() + public + returns (uint256) + { + return gasleft(); + } + + function getBlockNumber() + public + view + returns (uint256) + { + return block.number; + } } \ No newline at end of file diff --git a/packages/asset-swapper/src/index.ts b/packages/asset-swapper/src/index.ts index 82272123e6..89f7ee4626 100644 --- a/packages/asset-swapper/src/index.ts +++ b/packages/asset-swapper/src/index.ts @@ -113,6 +113,7 @@ export { SwapQuoterError, SwapQuoterOpts, SwapQuoterRfqOpts, + SamplerMetrics, } from './types'; export { affiliateFeeUtils } from './utils/affiliate_fee_utils'; export { diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index b0dc693e74..23c518f512 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -19,6 +19,7 @@ import { OptimizedMarketOrder, TokenAdjacencyGraph, } from './utils/market_operation_utils/types'; +export { SamplerMetrics } from './utils/market_operation_utils/types'; import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator'; import { MetricsProxy } from './utils/quote_requestor'; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/index.ts b/packages/asset-swapper/src/utils/market_operation_utils/index.ts index 21a02fba73..bc63e5ed34 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -158,6 +158,8 @@ export class MarketOperationUtils { // Call the sampler contract. const samplerPromise = this._sampler.executeAsync( + this._sampler.getBlockNumber(), + this._sampler.getGasLeft(), this._sampler.getTokenDecimals([makerToken, takerToken]), // Get native order fillable amounts. this._sampler.getLimitOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchangeProxy), @@ -184,6 +186,7 @@ export class MarketOperationUtils { takerAmount, ), this._sampler.isAddressContract(txOrigin), + this._sampler.getGasLeft(), ); // Refresh the cached pools asynchronously if required @@ -191,6 +194,8 @@ export class MarketOperationUtils { const [ [ + blockNumber, + gasBefore, tokenDecimals, orderFillableTakerAmounts, outputAmountPerEth, @@ -198,9 +203,14 @@ export class MarketOperationUtils { dexQuotes, rawTwoHopQuotes, isTxOriginContract, + gasAfter, ], ] = await Promise.all([samplerPromise]); + // Log the gas metrics + _opts.samplerMetrics?.logGasDetails({ gasBefore, gasAfter }); + _opts.samplerMetrics?.logBlockNumber(blockNumber); + // Filter out any invalid two hop quotes where we couldn't find a route const twoHopQuotes = rawTwoHopQuotes.filter( q => q && q.fillData && q.fillData.firstHopSource && q.fillData.secondHopSource, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts index 7afffec2f1..dda8fe04f7 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts @@ -130,6 +130,37 @@ export class DexOrderSampler extends SamplerOperations { BatchedOperationResult ]>; + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4, T5, T6, T7, T8, T9 + >(...ops: [T1, T2, T3, T4, T5, T6, T7, T8, T9]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 + >(...ops: [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + ]>; + /** * Run a series of operations from `DexOrderSampler.ops` in a single transaction. */ diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts index da51b1ebd3..8554d9e28c 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -158,6 +158,30 @@ export class SamplerOperations { }; } + public getGasLeft(): BatchedOperation { + return { + encodeCall: () => this._samplerContract.getGasLeft().getABIEncodedTransactionData(), + handleCallResults: (callResults: string) => + this._samplerContract.getABIDecodedReturnData('getGasLeft', callResults), + handleRevert: () => { + /* should never happen */ + throw new Error('Invalid result for getGasLeft'); + }, + }; + } + + public getBlockNumber(): BatchedOperation { + return { + encodeCall: () => this._samplerContract.getBlockNumber().getABIEncodedTransactionData(), + handleCallResults: (callResults: string) => + this._samplerContract.getABIDecodedReturnData('getBlockNumber', callResults), + handleRevert: () => { + /* should never happen */ + throw new Error('Invalid result for getBlockNumber'); + }, + }; + } + public getLimitOrderFillableTakerAmounts( orders: SignedNativeOrder[], exchangeAddress: string, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index a05fbedc49..b1848459b7 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -469,6 +469,28 @@ export interface GetMarketOrdersOpts { * Gas price to use for quote */ gasPrice: BigNumber; + + /** + * Sampler metrics for recording data on the sampler service and operations + */ + samplerMetrics?: SamplerMetrics; +} + +export interface SamplerMetrics { + /** + * Logs the gas information performed during a sampler call. + * + * @param data.gasBefore The gas remaining measured before any operations have been performed + * @param data.gasAfter The gas remaining measured after all operations have been performed + */ + logGasDetails(data: { gasBefore: BigNumber; gasAfter: BigNumber }): void; + + /** + * Logs the block number + * + * @param blockNumber block number of the sampler call + */ + logBlockNumber(blockNumber: BigNumber): void; } /** diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index 8f534d235a..f0e00296b6 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -23,6 +23,7 @@ import { POSITIVE_INF, SELL_SOURCE_FILTER_BY_CHAIN_ID, SOURCE_FLAGS, + ZERO_AMOUNT, } from '../src/utils/market_operation_utils/constants'; import { createFills } from '../src/utils/market_operation_utils/fills'; import { PoolsCache } from '../src/utils/market_operation_utils/pools_cache'; @@ -427,6 +428,8 @@ describe('MarketOperationUtils tests', () => { getTwoHopSellQuotes: (..._params: any[]) => [], getTwoHopBuyQuotes: (..._params: any[]) => [], isAddressContract: (..._params: any[]) => false, + getGasLeft: () => ZERO_AMOUNT, + getBlockNumber: () => ZERO_AMOUNT, }; const MOCK_SAMPLER = ({