protocol/packages/contracts/test/combinatorial_tests.ts

267 lines
12 KiB
TypeScript

import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { assetProxyUtils, crypto, orderHashUtils, OrderStateUtils } from '@0xproject/order-utils';
import { AssetProxyId, SignatureType, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import ethUtil = require('ethereumjs-util');
import 'make-promises-safe';
import { DummyERC20TokenContract } from '../src/contract_wrappers/generated/dummy_e_r_c20_token';
import { DummyERC721TokenContract } from '../src/contract_wrappers/generated/dummy_e_r_c721_token';
import { ERC20ProxyContract } from '../src/contract_wrappers/generated/e_r_c20_proxy';
import { ERC721ProxyContract } from '../src/contract_wrappers/generated/e_r_c721_proxy';
import {
CancelContractEventArgs,
ExchangeContract,
FillContractEventArgs,
} from '../src/contract_wrappers/generated/exchange';
import { artifacts } from '../src/utils/artifacts';
import { chaiSetup } from '../src/utils/chai_setup';
import { constants } from '../src/utils/constants';
import { ERC20Wrapper } from '../src/utils/erc20_wrapper';
import { ERC721Wrapper } from '../src/utils/erc721_wrapper';
import { ExchangeWrapper } from '../src/utils/exchange_wrapper';
import { NewOrderFactory } from '../src/utils/new_order_factory';
import { OrderInfoUtils } from '../src/utils/order_info_utils';
import { orderUtils } from '../src/utils/order_utils';
import { signingUtils } from '../src/utils/signing_utils';
import {
AssetDataScenario,
ContractName,
ERC20BalancesByOwner,
ExpirationTimeSecondsScenario,
FeeRecipientAddressScenario,
OrderAmountScenario,
OrderStatus,
} from '../src/utils/types';
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('Combinatorial tests', () => {
let newOrderFactory: NewOrderFactory;
let usedAddresses: string[];
let makerAddress: string;
let owner: string;
let takerAddress: string;
let feeRecipientAddress: string;
let erc20EighteenDecimalTokenA: DummyERC20TokenContract;
let erc20EighteenDecimalTokenB: DummyERC20TokenContract;
let erc20FiveDecimalTokenA: DummyERC20TokenContract;
let erc20FiveDecimalTokenB: DummyERC20TokenContract;
let zrxToken: DummyERC20TokenContract;
let erc721Token: DummyERC721TokenContract;
let exchange: ExchangeContract;
let erc20Proxy: ERC20ProxyContract;
let erc721Proxy: ERC721ProxyContract;
let erc20Balances: ERC20BalancesByOwner;
let exchangeWrapper: ExchangeWrapper;
let erc20Wrapper: ERC20Wrapper;
let erc721Wrapper: ERC721Wrapper;
let erc721MakerAssetIds: BigNumber[];
let erc721TakerAssetIds: BigNumber[];
let defaultMakerAssetAddress: string;
let defaultTakerAssetAddress: string;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
usedAddresses = [owner, makerAddress, takerAddress, feeRecipientAddress] = accounts;
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
const erc20EighteenDecimalTokenCount = 3;
const eighteenDecimals = new BigNumber(18);
[erc20EighteenDecimalTokenA, erc20EighteenDecimalTokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
erc20EighteenDecimalTokenCount,
eighteenDecimals,
);
const erc20FiveDecimalTokenCount = 2;
const fiveDecimals = new BigNumber(18);
[erc20FiveDecimalTokenA, erc20FiveDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
erc20FiveDecimalTokenCount,
fiveDecimals,
);
erc20Proxy = await erc20Wrapper.deployProxyAsync();
await erc20Wrapper.setBalancesAndAllowancesAsync();
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
erc721Proxy = await erc721Wrapper.deployProxyAsync();
await erc721Wrapper.setBalancesAndAllowancesAsync();
const erc721Balances = await erc721Wrapper.getBalancesAsync();
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange,
provider,
txDefaults,
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
);
exchangeWrapper = new ExchangeWrapper(exchange, provider);
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC721, erc721Proxy.address, owner);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
defaultMakerAssetAddress = erc20EighteenDecimalTokenA.address;
defaultTakerAssetAddress = erc20EighteenDecimalTokenB.address;
newOrderFactory = new NewOrderFactory(
usedAddresses,
zrxToken.address,
[erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address],
[erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address],
erc721Token,
erc721Balances,
exchange.address,
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe.only('Fill order', () => {
beforeEach(async () => {
erc20Balances = await erc20Wrapper.getBalancesAsync();
});
it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
const order = newOrderFactory.generateOrder(
FeeRecipientAddressScenario.EthUserAddress,
OrderAmountScenario.NonZero,
OrderAmountScenario.NonZero,
OrderAmountScenario.Zero,
OrderAmountScenario.Zero,
ExpirationTimeSecondsScenario.InFuture,
AssetDataScenario.ERC20NonZRXEighteenDecimals,
AssetDataScenario.ERC20NonZRXEighteenDecimals,
);
// TODO: Permute signature types
// TODO: Sign order (for now simply ECSign)
const orderHashBuff = orderHashUtils.getOrderHashBuff(order);
const privateKey = constants.TESTRPC_PRIVATE_KEYS[usedAddresses.indexOf(makerAddress)];
const signature = signingUtils.signMessage(orderHashBuff, privateKey, SignatureType.EthSign);
const signedOrder = {
...order,
signature: `0x${signature.toString('hex')}`,
};
console.log('signedOrder', signedOrder);
// TODO: Get orderRelevantState
const orderInfoUtils = new OrderInfoUtils(exchange, erc20Wrapper, zrxToken.address);
// 1. How much of this order can I fill?
const fillableTakerAssetAmount = await orderInfoUtils.getFillableTakerAssetAmountAsync(
signedOrder,
takerAddress,
);
console.log('fillableTakerAssetAmount', fillableTakerAssetAmount);
// TODO: Decide how much to fill (all, some)
const takerFillAmount = fillableTakerAssetAmount.div(2); // some for now
// 2. If I fill it by X, what are the resulting balances/allowances/filled amounts expected?
// NOTE: we can't use orderStateUtils for this :( We need to do this ourselves.
// This doesn't include taker balance/allowance checks...
/*
Inputs:
- signedOrder
- takerAddress
Outputs:
- Check fillable amount
- maker token balance & allowance
- maker ZRX balance & allowance
- taker token balance & allowance
- taker ZRX balance & allowance
Test:
- If fillable >= fillAmount:
- check that filled by fillAmount
- check makerBalance
*/
// signedOrder = orderFactory.newSignedOrder({
// makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
// takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
// }); );
//
// const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
// orderHashUtils.getOrderHashHex(signedOrder),
// );
// expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
//
// const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
// await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
//
// const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
// orderHashUtils.getOrderHashHex(signedOrder),
// );
// expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
//
// const newBalances = await erc20Wrapper.getBalancesAsync();
//
// const makerAssetFilledAmount = takerAssetFillAmount
// .times(signedOrder.makerAssetAmount)
// .dividedToIntegerBy(signedOrder.takerAssetAmount);
// const makerFeePaid = signedOrder.makerFee
// .times(makerAssetFilledAmount)
// .dividedToIntegerBy(signedOrder.makerAssetAmount);
// const takerFeePaid = signedOrder.takerFee
// .times(makerAssetFilledAmount)
// .dividedToIntegerBy(signedOrder.makerAssetAmount);
// expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
// erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
// );
// expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
// erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
// );
// expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
// erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
// );
// expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
// erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
// );
// expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
// erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
// );
// expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
// erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
// );
// expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
// erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
// );
});
});
});