diff --git a/src/handlers/meta_transaction_handlers.ts b/src/handlers/meta_transaction_handlers.ts index 1fe618517..c5a7bdc69 100644 --- a/src/handlers/meta_transaction_handlers.ts +++ b/src/handlers/meta_transaction_handlers.ts @@ -23,7 +23,7 @@ import { logger } from '../logger'; import { isAPIError, isRevertError } from '../middleware/error_handling'; import { schemas } from '../schemas/schemas'; import { MetaTransactionService } from '../services/meta_transaction_service'; -import { GetTransactionRequestParams, ZeroExTransactionWithoutDomain } from '../types'; +import { GetMetaTransactionPriceResponse, GetTransactionRequestParams, ZeroExTransactionWithoutDomain } from '../types'; import { parseUtils } from '../utils/parse_utils'; import { schemaUtils } from '../utils/schema_utils'; import { findTokenAddressOrThrowApiError } from '../utils/token_metadata_utils'; @@ -147,12 +147,13 @@ export class MetaTransactionHandlers { }, 'price', ); - const metaTransactionPriceResponse = { + const metaTransactionPriceResponse: GetMetaTransactionPriceResponse = { price: metaTransactionPrice.price, buyAmount: metaTransactionPrice.buyAmount, sellAmount: metaTransactionPrice.sellAmount, sellTokenAddress, buyTokenAddress, + sources: metaTransactionPrice.sources, }; res.status(HttpStatus.OK).send(metaTransactionPriceResponse); } catch (e) { diff --git a/src/handlers/swap_handlers.ts b/src/handlers/swap_handlers.ts index 5d7788bd5..9a82921e1 100644 --- a/src/handlers/swap_handlers.ts +++ b/src/handlers/swap_handlers.ts @@ -17,7 +17,12 @@ import { isAPIError, isRevertError } from '../middleware/error_handling'; import { schemas } from '../schemas/schemas'; import { SwapService } from '../services/swap_service'; import { TokenMetadatasForChains } from '../token_metadatas_for_networks'; -import { CalculateSwapQuoteParams, GetSwapQuoteRequestParams, GetSwapQuoteResponse } from '../types'; +import { + CalculateSwapQuoteParams, + GetSwapPriceResponse, + GetSwapQuoteRequestParams, + GetSwapQuoteResponse, +} from '../types'; import { parseUtils } from '../utils/parse_utils'; import { schemaUtils } from '../utils/schema_utils'; import { @@ -70,7 +75,19 @@ export class SwapHandlers { const params = parseGetSwapQuoteRequestParams(req, 'price'); params.skipValidation = true; const quote = await this._calculateSwapQuoteAsync(params); - const { price, value, gasPrice, gas, protocolFee, buyAmount, sellAmount, sources, orders } = quote; + const { + price, + value, + gasPrice, + gas, + protocolFee, + buyAmount, + sellAmount, + sources, + orders, + buyTokenAddress, + sellTokenAddress, + } = quote; logger.info({ indicativeQuoteServed: { taker: params.takerAddress, @@ -82,7 +99,20 @@ export class SwapHandlers { makers: orders.map(o => o.makerAddress), }, }); - res.status(HttpStatus.OK).send({ price, value, gasPrice, gas, protocolFee, buyAmount, sellAmount, sources }); + + const response: GetSwapPriceResponse = { + price, + value, + gasPrice, + gas, + protocolFee, + buyTokenAddress, + buyAmount, + sellTokenAddress, + sellAmount, + sources, + }; + res.status(HttpStatus.OK).send(response); } // tslint:disable-next-line:prefer-function-over-method public async getTokenPricesAsync(req: express.Request, res: express.Response): Promise { diff --git a/src/services/meta_transaction_service.ts b/src/services/meta_transaction_service.ts index 4cb45a3c0..d381ac89a 100644 --- a/src/services/meta_transaction_service.ts +++ b/src/services/meta_transaction_service.ts @@ -138,8 +138,8 @@ export class MetaTransactionService { const response: CalculateMetaTransactionPriceResponse = { takerAddress, - sellAmount, - buyAmount, + buyAmount: makerAssetAmount, + sellAmount: totalTakerAssetAmount, price, swapQuote, sources: serviceUtils.convertSourceBreakdownToArray(swapQuote.sourceBreakdown), diff --git a/src/types.ts b/src/types.ts index f27f54b59..6b9b809f0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -369,6 +369,22 @@ export interface Price { price: BigNumber; } +interface BasePriceResponse { + price: BigNumber; + buyAmount: BigNumber; + sellAmount: BigNumber; + sellTokenAddress: string; + buyTokenAddress: string; + sources: GetSwapQuoteResponseLiquiditySource[]; +} + +export interface GetSwapPriceResponse extends BasePriceResponse { + value: BigNumber; + gasPrice: BigNumber; + gas: BigNumber; + protocolFee: BigNumber; +} + export type GetTokenPricesResponse = Price[]; export interface GetMetaTransactionQuoteResponse { @@ -381,11 +397,7 @@ export interface GetMetaTransactionQuoteResponse { sources: GetSwapQuoteResponseLiquiditySource[]; } -export interface GetMetaTransactionPriceResponse { - price: BigNumber; - buyAmount: BigNumber; - sellAmount: BigNumber; -} +export interface GetMetaTransactionPriceResponse extends BasePriceResponse {} // takerAddress, sellAmount, buyAmount, swapQuote, price export interface CalculateMetaTransactionPriceResponse { diff --git a/test/meta_transaction_test.ts b/test/meta_transaction_test.ts index 698257ea2..9b50742ce 100644 --- a/test/meta_transaction_test.ts +++ b/test/meta_transaction_test.ts @@ -17,6 +17,7 @@ import { GetMetaTransactionQuoteResponse } from '../src/types'; import { setupApiAsync, setupMeshAsync, teardownApiAsync, teardownMeshAsync } from './utils/deployment'; import { constructRoute, httpGetAsync, httpPostAsync } from './utils/http_utils'; import { DEFAULT_MAKER_ASSET_AMOUNT, MeshTestUtils } from './utils/mesh_test_utils'; +import { liquiditySources0xOnly } from './utils/mocks'; const SUITE_NAME = 'meta transactions tests'; @@ -212,6 +213,8 @@ describe(SUITE_NAME, () => { context('success tests', () => { let meshUtils: MeshTestUtils; + const price = '1'; + const sellAmount = calculateSellAmount(buyAmount, price); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -239,10 +242,12 @@ describe(SUITE_NAME, () => { expect(response.type).to.be.eq('application/json'); expect(response.status).to.be.eq(HttpStatus.OK); expect(response.body).to.be.deep.eq({ - price: '1', + price, buyAmount, + sellAmount, sellTokenAddress, buyTokenAddress, + sources: liquiditySources0xOnly, }); }); @@ -260,17 +265,21 @@ describe(SUITE_NAME, () => { expect(response.type).to.be.eq('application/json'); expect(response.status).to.be.eq(HttpStatus.OK); expect(response.body).to.be.deep.eq({ - price: '1', + price, buyAmount, + sellAmount, sellTokenAddress, buyTokenAddress, + sources: liquiditySources0xOnly, }); }); it('should show the price of the combination of the two orders in Mesh', async () => { const validationResults = await meshUtils.addOrdersWithPricesAsync([1, 2]); expect(validationResults.rejected.length, 'mesh should not reject any orders').to.be.eq(0); + const largeOrderPrice = '1.5'; const largeBuyAmount = DEFAULT_MAKER_ASSET_AMOUNT.times(2).toString(); + const largeSellAmount = calculateSellAmount(largeBuyAmount, largeOrderPrice); const route = constructRoute({ baseRoute: `${META_TRANSACTION_PATH}/price`, queryParams: { @@ -283,10 +292,12 @@ describe(SUITE_NAME, () => { expect(response.type).to.be.eq('application/json'); expect(response.status).to.be.eq(HttpStatus.OK); expect(response.body).to.be.deep.eq({ - price: '1.5', + price: largeOrderPrice, buyAmount: largeBuyAmount, + sellAmount: largeSellAmount, sellTokenAddress, buyTokenAddress, + sources: liquiditySources0xOnly, }); }); }); @@ -366,18 +377,7 @@ describe(SUITE_NAME, () => { buyAmount: testCase.expectedBuyAmount, sellAmount: calculateSellAmount(testCase.expectedBuyAmount, testCase.expectedPrice), // NOTE(jalextowle): 0x is the only source that is currently being tested. - sources: [ - { name: '0x', proportion: '1' }, - { name: 'Uniswap', proportion: '0' }, - { name: 'Eth2Dai', proportion: '0' }, - { name: 'Kyber', proportion: '0' }, - { name: 'Curve_USDC_DAI', proportion: '0' }, - { name: 'Curve_USDC_DAI_USDT', proportion: '0' }, - { name: 'Curve_USDC_DAI_USDT_TUSD', proportion: '0' }, - { name: 'Curve_USDC_DAI_USDT_BUSD', proportion: '0' }, - { name: 'Curve_USDC_DAI_USDT_SUSD', proportion: '0' }, - { name: 'LiquidityProvider', proportion: '0' }, - ], + sources: liquiditySources0xOnly, }); } @@ -547,8 +547,10 @@ describe(SUITE_NAME, () => { expect(response.body).to.be.deep.eq({ price, buyAmount, + sellAmount, sellTokenAddress, buyTokenAddress, + sources: liquiditySources0xOnly, }); }); @@ -659,6 +661,7 @@ describe(SUITE_NAME, () => { buyAmount: largeBuyAmount, sellTokenAddress, buyTokenAddress, + sources: liquiditySources0xOnly, }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 1eefe3301..427e92c4b 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -26,3 +26,16 @@ export const rfqtIndicativeQuoteResponse = { takerAssetData: '0xf47261b00000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082', expirationTimeSeconds: '1903620548', // in the year 2030 }; + +export const liquiditySources0xOnly = [ + { name: '0x', proportion: '1' }, + { name: 'Uniswap', proportion: '0' }, + { name: 'Eth2Dai', proportion: '0' }, + { name: 'Kyber', proportion: '0' }, + { name: 'Curve_USDC_DAI', proportion: '0' }, + { name: 'Curve_USDC_DAI_USDT', proportion: '0' }, + { name: 'Curve_USDC_DAI_USDT_TUSD', proportion: '0' }, + { name: 'Curve_USDC_DAI_USDT_BUSD', proportion: '0' }, + { name: 'Curve_USDC_DAI_USDT_SUSD', proportion: '0' }, + { name: 'LiquidityProvider', proportion: '0' }, +];