From ab5e021bda5cc8e39d8595580c09c3540a09aff5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 7 Jun 2018 18:00:13 +0200 Subject: POC: Generates an order from spec, get's the amount fillable --- packages/contracts/test/combinatorial_tests.ts | 266 +++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 packages/contracts/test/combinatorial_tests.ts (limited to 'packages/contracts/test') diff --git a/packages/contracts/test/combinatorial_tests.ts b/packages/contracts/test/combinatorial_tests.ts new file mode 100644 index 000000000..7a118f6ac --- /dev/null +++ b/packages/contracts/test/combinatorial_tests.ts @@ -0,0 +1,266 @@ +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)), + // ); + }); + }); +}); -- cgit