* switch @0x/contract-wrappers to generated wrappers - remove TransactionEncoder - move TokenUtils to @0x/dev-utils - detailed changes in #2040
230 lines
11 KiB
TypeScript
230 lines
11 KiB
TypeScript
import { ContractAddresses, ContractWrappers } from '@0x/contract-wrappers';
|
|
import { BlockchainLifecycle, tokenUtils } from '@0x/dev-utils';
|
|
import { FillScenarios } from '@0x/fill-scenarios';
|
|
import { assetDataUtils } from '@0x/order-utils';
|
|
import { MarketOperation, SignedOrder } from '@0x/types';
|
|
import { BigNumber } from '@0x/utils';
|
|
import * as chai from 'chai';
|
|
import 'mocha';
|
|
|
|
import { SwapQuote } from '../src';
|
|
import { constants } from '../src/constants';
|
|
import { ExchangeSwapQuoteConsumer } from '../src/quote_consumers/exchange_swap_quote_consumer';
|
|
import {
|
|
ExchangeMarketBuySmartContractParams,
|
|
ExchangeMarketSellSmartContractParams,
|
|
MarketBuySwapQuote,
|
|
MarketSellSwapQuote,
|
|
} from '../src/types';
|
|
|
|
import { chaiSetup } from './utils/chai_setup';
|
|
import { migrateOnceAsync } from './utils/migrate';
|
|
import { getFullyFillableSwapQuoteWithNoFees } from './utils/swap_quote';
|
|
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
|
|
|
chaiSetup.configure();
|
|
const expect = chai.expect;
|
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
|
|
|
const ONE_ETH_IN_WEI = new BigNumber(1000000000000000000);
|
|
const TESTRPC_NETWORK_ID = 50;
|
|
const FILLABLE_AMOUNTS = [new BigNumber(3), new BigNumber(2), new BigNumber(5)].map(value =>
|
|
value.multipliedBy(ONE_ETH_IN_WEI),
|
|
);
|
|
|
|
describe('ExchangeSwapQuoteConsumer', () => {
|
|
let contractWrappers: ContractWrappers;
|
|
let userAddresses: string[];
|
|
let coinbaseAddress: string;
|
|
let makerAddress: string;
|
|
let takerAddress: string;
|
|
let fillScenarios: FillScenarios;
|
|
let feeRecipient: string;
|
|
let makerTokenAddress: string;
|
|
let takerTokenAddress: string;
|
|
let makerAssetData: string;
|
|
let takerAssetData: string;
|
|
let wethAssetData: string;
|
|
let contractAddresses: ContractAddresses;
|
|
|
|
const networkId = TESTRPC_NETWORK_ID;
|
|
|
|
let orders: SignedOrder[];
|
|
let marketSellSwapQuote: SwapQuote;
|
|
let marketBuySwapQuote: SwapQuote;
|
|
let swapQuoteConsumer: ExchangeSwapQuoteConsumer;
|
|
|
|
before(async () => {
|
|
contractAddresses = await migrateOnceAsync();
|
|
await blockchainLifecycle.startAsync();
|
|
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
|
fillScenarios = new FillScenarios(
|
|
provider,
|
|
userAddresses,
|
|
contractAddresses.zrxToken,
|
|
contractAddresses.exchange,
|
|
contractAddresses.erc20Proxy,
|
|
contractAddresses.erc721Proxy,
|
|
);
|
|
const config = {
|
|
networkId,
|
|
contractAddresses,
|
|
};
|
|
contractWrappers = new ContractWrappers(provider, config);
|
|
[coinbaseAddress, takerAddress, makerAddress, feeRecipient] = userAddresses;
|
|
[makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
|
|
[makerAssetData, takerAssetData, wethAssetData] = [
|
|
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
|
|
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
|
|
assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken),
|
|
];
|
|
});
|
|
after(async () => {
|
|
await blockchainLifecycle.revertAsync();
|
|
});
|
|
beforeEach(async () => {
|
|
await blockchainLifecycle.startAsync();
|
|
orders = [];
|
|
for (const fillableAmmount of FILLABLE_AMOUNTS) {
|
|
const order = await fillScenarios.createFillableSignedOrderAsync(
|
|
makerAssetData,
|
|
takerAssetData,
|
|
makerAddress,
|
|
takerAddress,
|
|
fillableAmmount,
|
|
);
|
|
orders.push(order);
|
|
}
|
|
|
|
marketSellSwapQuote = getFullyFillableSwapQuoteWithNoFees(
|
|
makerAssetData,
|
|
takerAssetData,
|
|
orders,
|
|
MarketOperation.Sell,
|
|
);
|
|
|
|
marketBuySwapQuote = getFullyFillableSwapQuoteWithNoFees(
|
|
makerAssetData,
|
|
takerAssetData,
|
|
orders,
|
|
MarketOperation.Buy,
|
|
);
|
|
|
|
swapQuoteConsumer = new ExchangeSwapQuoteConsumer(provider, {
|
|
networkId,
|
|
});
|
|
});
|
|
afterEach(async () => {
|
|
await blockchainLifecycle.revertAsync();
|
|
});
|
|
describe('executeSwapQuoteOrThrowAsync', () => {
|
|
/*
|
|
* Testing that SwapQuoteConsumer logic correctly performs a execution (doesn't throw or revert)
|
|
* Does not test the validity of the state change performed by the forwarder smart contract
|
|
*/
|
|
it('should perform a marketSell execution when provided a MarketSell type swapQuote', async () => {
|
|
let makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
let takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketSellSwapQuote, { takerAddress });
|
|
makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
});
|
|
it('should perform a marketBuy execution when provided a MarketBuy type swapQuote', async () => {
|
|
let makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
let takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketBuySwapQuote, { takerAddress });
|
|
makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
});
|
|
});
|
|
|
|
describe('getSmartContractParamsOrThrow', () => {
|
|
describe('valid swap quote', async () => {
|
|
// TODO(david) Check for valid MethodAbi
|
|
it('provide correct and optimized smart contract params for a marketSell SwapQuote', async () => {
|
|
const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync(
|
|
marketSellSwapQuote,
|
|
{},
|
|
);
|
|
expect(toAddress).to.deep.equal(contractWrappers.exchange.address);
|
|
const { takerAssetFillAmount, signatures, type } = params as ExchangeMarketSellSmartContractParams;
|
|
expect(type).to.deep.equal(MarketOperation.Sell);
|
|
expect(takerAssetFillAmount).to.bignumber.equal(
|
|
(marketSellSwapQuote as MarketSellSwapQuote).takerAssetFillAmount,
|
|
);
|
|
const orderSignatures = marketSellSwapQuote.orders.map(order => order.signature);
|
|
expect(signatures).to.deep.equal(orderSignatures);
|
|
});
|
|
it('provide correct and optimized smart contract params for a marketBuy SwapQuote', async () => {
|
|
const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync(
|
|
marketBuySwapQuote,
|
|
{},
|
|
);
|
|
expect(toAddress).to.deep.equal(contractWrappers.exchange.address);
|
|
const { makerAssetFillAmount, signatures, type } = params as ExchangeMarketBuySmartContractParams;
|
|
expect(type).to.deep.equal(MarketOperation.Buy);
|
|
expect(makerAssetFillAmount).to.bignumber.equal(
|
|
(marketBuySwapQuote as MarketBuySwapQuote).makerAssetFillAmount,
|
|
);
|
|
const orderSignatures = marketSellSwapQuote.orders.map(order => order.signature);
|
|
expect(signatures).to.deep.equal(orderSignatures);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getCalldataOrThrow', () => {
|
|
describe('valid swap quote', async () => {
|
|
it('provide correct and optimized calldata options with default options for a marketSell SwapQuote (no affiliate fees)', async () => {
|
|
let makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
let takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
const { calldataHexString, toAddress } = await swapQuoteConsumer.getCalldataOrThrowAsync(
|
|
marketSellSwapQuote,
|
|
{},
|
|
);
|
|
expect(toAddress).to.deep.equal(contractWrappers.exchange.address);
|
|
await web3Wrapper.sendTransactionAsync({
|
|
from: takerAddress,
|
|
to: toAddress,
|
|
data: calldataHexString,
|
|
gas: 4000000,
|
|
});
|
|
makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
});
|
|
it('provide correct and optimized calldata options with default options for a marketBuy SwapQuote (no affiliate fees)', async () => {
|
|
let makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
let takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
const { calldataHexString, toAddress } = await swapQuoteConsumer.getCalldataOrThrowAsync(
|
|
marketBuySwapQuote,
|
|
{},
|
|
);
|
|
expect(toAddress).to.deep.equal(contractWrappers.exchange.address);
|
|
await web3Wrapper.sendTransactionAsync({
|
|
from: takerAddress,
|
|
to: toAddress,
|
|
data: calldataHexString,
|
|
gas: 4000000,
|
|
});
|
|
makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
|
takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
|
|
expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI));
|
|
expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
|
});
|
|
});
|
|
});
|
|
});
|