267 lines
12 KiB
TypeScript
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)),
|
|
// );
|
|
});
|
|
});
|
|
});
|