Files
protocol/apps-node/rfq-api/test/handlers/dummy_mm_handler_test.ts
2023-03-09 11:19:11 -07:00

274 lines
11 KiB
TypeScript

import { OtcOrder } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils';
import * as express from 'express';
import * as asyncHandler from 'express-async-handler';
import * as HttpStatus from 'http-status-codes';
import * as supertest from 'supertest';
import { DummyMMHandlers } from '../../src/handlers/dummy_mm_handler';
import { getSignerFromHash } from '../../src/utils/signature_utils';
const POLYGON_CHAIN_ID = 137;
const USDC_POLYGON = '0x2791bca1f2de4661ed88a30c99a7a9449aa84174';
const USDT_POLYGON = '0xc2132d05d31c914a87c6611c10748aeb04b58e8f';
const MM_ADDRESS = '0x06754422cf9f54ae0e67d42fd788b33d8eb4c5d5';
const INTEGRATOR_ID = '74188355-c85b-4f18-9de4-6dec3ec61b8d';
const dummyMMHandler = new DummyMMHandlers();
const emptyOtcOrder = new OtcOrder();
const emptyOtcOrderParam = {
maker: emptyOtcOrder.maker,
taker: emptyOtcOrder.taker,
makerAmount: emptyOtcOrder.makerAmount.toString(),
takerAmount: emptyOtcOrder.takerAmount.toString(),
makerToken: emptyOtcOrder.makerToken,
takerToken: emptyOtcOrder.takerToken,
txOrigin: emptyOtcOrder.txOrigin,
expiryAndNonce: emptyOtcOrder.expiryAndNonce.toString(),
chainId: emptyOtcOrder.chainId.toString(),
verifyingContract: emptyOtcOrder.verifyingContract,
};
const acceptedOtcOrder = new OtcOrder({
makerToken: USDC_POLYGON,
takerToken: USDT_POLYGON,
takerAmount: new BigNumber('200'),
chainId: POLYGON_CHAIN_ID,
});
const acceptedOtcOrderParam = {
maker: acceptedOtcOrder.maker,
taker: acceptedOtcOrder.taker,
makerAmount: acceptedOtcOrder.makerAmount.toString(),
takerAmount: acceptedOtcOrder.takerAmount.toString(),
makerToken: acceptedOtcOrder.makerToken,
takerToken: acceptedOtcOrder.takerToken,
txOrigin: acceptedOtcOrder.txOrigin,
expiryAndNonce: acceptedOtcOrder.expiryAndNonce.toString(),
chainId: acceptedOtcOrder.chainId.toString(),
verifyingContract: acceptedOtcOrder.verifyingContract,
};
const refusedOtcOrder = new OtcOrder({
makerToken: USDC_POLYGON,
takerToken: USDT_POLYGON,
takerAmount: new BigNumber('1000000'),
chainId: POLYGON_CHAIN_ID,
});
const refusedOtcOrderParam = {
maker: refusedOtcOrder.maker,
taker: refusedOtcOrder.taker,
makerAmount: refusedOtcOrder.makerAmount.toString(),
takerAmount: refusedOtcOrder.takerAmount.toString(),
makerToken: refusedOtcOrder.makerToken,
takerToken: refusedOtcOrder.takerToken,
txOrigin: refusedOtcOrder.txOrigin,
expiryAndNonce: refusedOtcOrder.expiryAndNonce.toString(),
chainId: refusedOtcOrder.chainId.toString(),
verifyingContract: refusedOtcOrder.verifyingContract,
};
describe('DummyMMHandlers', () => {
describe('signRfqtV2Async', () => {
it('returns BAD_REQUEST when order hash does not match with order hash query param', async () => {
const response = await supertest(
express()
.use(express.json())
.post('/rfqt/v2/sign', asyncHandler(dummyMMHandler.signRfqtV2Async.bind(dummyMMHandler))),
)
.post('/rfqt/v2/sign')
.set('Content-type', 'application/json')
.send({
order: emptyOtcOrderParam,
orderHash: '0xrandom',
feeAmount: '10',
feeToken: '0xfee',
expiry: '20',
});
expect(response.statusCode).toEqual(HttpStatus.BAD_REQUEST);
});
it('returns NO_CONTENT when tokens in the order are not part of provided liquity', async () => {
const response = await supertest(
express()
.use(express.json())
.post('/rfqt/v2/sign', asyncHandler(dummyMMHandler.signRfqtV2Async.bind(dummyMMHandler))),
)
.post('/rfqt/v2/sign')
.set('Content-type', 'application/json')
.send({
order: emptyOtcOrderParam,
orderHash: emptyOtcOrder.getHash(),
feeAmount: '10',
feeToken: '0xfee',
expiry: '20',
});
expect(response.statusCode).toEqual(HttpStatus.NO_CONTENT);
});
it('returns NO_CONTENT when the market marker refuses to sign the order', async () => {
const response = await supertest(
express()
.use(express.json())
.post('/rfqt/v2/sign', asyncHandler(dummyMMHandler.signRfqtV2Async.bind(dummyMMHandler))),
)
.post('/rfqt/v2/sign')
.set('Content-type', 'application/json')
.send({
order: refusedOtcOrderParam,
orderHash: refusedOtcOrder.getHash(),
feeAmount: '10',
feeToken: '0xfee',
expiry: '20',
});
expect(response.statusCode).toEqual(HttpStatus.NO_CONTENT);
});
it('returns OK when the market marker signs', async () => {
const response = await supertest(
express()
.use(express.json())
.post('/rfqt/v2/sign', asyncHandler(dummyMMHandler.signRfqtV2Async.bind(dummyMMHandler))),
)
.post('/rfqt/v2/sign')
.set('Content-type', 'application/json')
.send({
order: acceptedOtcOrderParam,
orderHash: acceptedOtcOrder.getHash(),
feeAmount: '10',
feeToken: '0xfee',
expiry: '20',
});
expect(response.statusCode).toEqual(HttpStatus.OK);
const signer = getSignerFromHash(acceptedOtcOrder.getHash(), response.body.makerSignature);
expect(signer).toEqual(MM_ADDRESS);
});
});
describe('getQuoteRfqtV2Async', () => {
it('returns BAD_REQUEST when missing integrator id', async () => {
const response = await supertest(
express().get('/rfqt/v2/quote', asyncHandler(dummyMMHandler.getQuoteRfqtV2Async.bind(dummyMMHandler))),
)
.get('/rfqt/v2/quote')
.query({
sellTokenAddress: USDC_POLYGON,
buyTokenAddress: USDT_POLYGON,
sellAmountBaseUnits: '200',
txOrigin: '0x123456789',
takerAddress: '0x123456789',
feeToken: USDC_POLYGON,
feeAmount: '10',
chainId: POLYGON_CHAIN_ID.toString(),
});
expect(response.statusCode).toEqual(HttpStatus.BAD_REQUEST);
});
it('returns BAD_REQUEST when integrator id is not whitelisted', async () => {
const response = await supertest(
express().get('/rfqt/v2/quote', asyncHandler(dummyMMHandler.getQuoteRfqtV2Async.bind(dummyMMHandler))),
)
.get('/rfqt/v2/quote')
.set('0x-integrator-id', '0123')
.query({
sellTokenAddress: USDC_POLYGON,
buyTokenAddress: USDT_POLYGON,
sellAmountBaseUnits: '200',
txOrigin: '0x123456789',
takerAddress: '0x123456789',
feeToken: USDC_POLYGON,
feeAmount: '10',
chainId: POLYGON_CHAIN_ID.toString(),
integratorId: '0123',
});
expect(response.statusCode).toEqual(HttpStatus.BAD_REQUEST);
});
it('returns NO_CONTENT when tokens in the order are not part of provided liquity', async () => {
const response = await supertest(
express().get('/rfqt/v2/quote', asyncHandler(dummyMMHandler.getQuoteRfqtV2Async.bind(dummyMMHandler))),
)
.get('/rfqt/v2/quote')
.set('0x-integrator-id', INTEGRATOR_ID)
.query({
sellTokenAddress: '0x1234',
buyTokenAddress: USDT_POLYGON,
sellAmountBaseUnits: '200',
txOrigin: '0x123456789',
takerAddress: '0x123456789',
feeToken: USDC_POLYGON,
feeAmount: '10',
chainId: POLYGON_CHAIN_ID.toString(),
integratorId: INTEGRATOR_ID,
});
expect(response.statusCode).toEqual(HttpStatus.NO_CONTENT);
});
it('returns NO_CONTENT when buy/sell amount > 2', async () => {
const response = await supertest(
express().get('/rfqt/v2/quote', asyncHandler(dummyMMHandler.getQuoteRfqtV2Async.bind(dummyMMHandler))),
)
.get('/rfqt/v2/quote')
.set('0x-integrator-id', INTEGRATOR_ID)
.query({
sellTokenAddress: USDC_POLYGON,
buyTokenAddress: USDT_POLYGON,
sellAmountBaseUnits: '20000000000',
txOrigin: '0x123456789',
takerAddress: '0x123456789',
feeToken: USDC_POLYGON,
feeAmount: '10',
chainId: POLYGON_CHAIN_ID.toString(),
integratorId: INTEGRATOR_ID,
});
expect(response.statusCode).toEqual(HttpStatus.NO_CONTENT);
});
it('returns NO_CONTENT when trading amount is considered odd', async () => {
const response = await supertest(
express().get('/rfqt/v2/quote', asyncHandler(dummyMMHandler.getQuoteRfqtV2Async.bind(dummyMMHandler))),
)
.get('/rfqt/v2/quote')
.set('0x-integrator-id', INTEGRATOR_ID)
.query({
sellTokenAddress: USDC_POLYGON,
buyTokenAddress: USDT_POLYGON,
sellAmountBaseUnits: '1000000',
txOrigin: '0x123456789',
takerAddress: '0x123456789',
feeToken: USDC_POLYGON,
feeAmount: '10',
chainId: POLYGON_CHAIN_ID.toString(),
integratorId: INTEGRATOR_ID,
});
expect(response.statusCode).toEqual(HttpStatus.NO_CONTENT);
});
it('returns OK the market maker signs the order', async () => {
const response = await supertest(
express().get('/rfqt/v2/quote', asyncHandler(dummyMMHandler.getQuoteRfqtV2Async.bind(dummyMMHandler))),
)
.get('/rfqt/v2/quote')
.set('0x-integrator-id', INTEGRATOR_ID)
.query({
sellTokenAddress: USDC_POLYGON,
buyTokenAddress: USDT_POLYGON,
sellAmountBaseUnits: '200',
txOrigin: '0x123456789',
takerAddress: '0x123456789',
feeToken: USDC_POLYGON,
feeAmount: '10',
chainId: POLYGON_CHAIN_ID.toString(),
integratorId: INTEGRATOR_ID,
});
expect(response.statusCode).toEqual(HttpStatus.OK);
});
});
});