202 lines
9.5 KiB
TypeScript
202 lines
9.5 KiB
TypeScript
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
|
import { ForwarderContract, IExchangeV2Contract } from '@0x/contracts-exchange-forwarder';
|
|
import {
|
|
blockchainTests,
|
|
constants,
|
|
expect,
|
|
getLatestBlockTimestampAsync,
|
|
orderHashUtils,
|
|
signingUtils,
|
|
} from '@0x/contracts-test-utils';
|
|
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
|
import { Order, SignatureType, SignedOrder } from '@0x/types';
|
|
import { BigNumber } from '@0x/utils';
|
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
import * as ethUtil from 'ethereumjs-util';
|
|
|
|
import { contractAddresses } from '../mainnet_fork_utils';
|
|
|
|
import { SignedV2Order } from './types';
|
|
|
|
blockchainTests.fork.resets('Forwarder mainnet tests', env => {
|
|
const forwarder = new ForwarderContract(contractAddresses.forwarder, env.provider, env.txDefaults);
|
|
const exchangeV2 = new IExchangeV2Contract(contractAddresses.exchangeV2, env.provider, env.txDefaults);
|
|
const wethAssetData = assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken);
|
|
const v2OrderId = '0x770501f8';
|
|
let makerAddress: string;
|
|
let takerAddress: string;
|
|
let makerAssetData: string;
|
|
let makerToken: DummyERC20TokenContract;
|
|
let makerPrivateKey: Buffer;
|
|
|
|
before(async () => {
|
|
[makerAddress, takerAddress] = await env.web3Wrapper.getAvailableAddressesAsync();
|
|
makerToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
|
erc20Artifacts.DummyERC20Token,
|
|
env.provider,
|
|
env.txDefaults,
|
|
erc20Artifacts,
|
|
constants.DUMMY_TOKEN_NAME,
|
|
constants.DUMMY_TOKEN_SYMBOL,
|
|
constants.DUMMY_TOKEN_DECIMALS,
|
|
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
|
|
);
|
|
await makerToken.setBalance(makerAddress, constants.INITIAL_ERC20_BALANCE).awaitTransactionSuccessAsync();
|
|
await makerToken
|
|
.approve(contractAddresses.erc20Proxy, constants.INITIAL_ERC20_ALLOWANCE)
|
|
.awaitTransactionSuccessAsync({ from: makerAddress });
|
|
makerAssetData = assetDataUtils.encodeERC20AssetData(makerToken.address);
|
|
makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[0];
|
|
});
|
|
|
|
async function createOrderAsync(orderParams: Partial<Order> = {}): Promise<SignedOrder | SignedV2Order> {
|
|
const currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
|
const fifteenMinutesInSeconds = 15 * 60;
|
|
const order = {
|
|
chainId: 1,
|
|
exchangeAddress: contractAddresses.exchange,
|
|
makerAddress,
|
|
takerAddress: constants.NULL_ADDRESS,
|
|
senderAddress: constants.NULL_ADDRESS,
|
|
feeRecipientAddress: constants.NULL_ADDRESS,
|
|
expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(fifteenMinutesInSeconds),
|
|
salt: generatePseudoRandomSalt(),
|
|
makerAssetData,
|
|
takerAssetData: wethAssetData,
|
|
makerFeeAssetData: makerAssetData,
|
|
takerFeeAssetData: wethAssetData,
|
|
makerAssetAmount: constants.INITIAL_ERC20_BALANCE.dividedToIntegerBy(2),
|
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(0.001, 18),
|
|
makerFee: constants.ZERO_AMOUNT,
|
|
takerFee: constants.ZERO_AMOUNT,
|
|
...orderParams,
|
|
};
|
|
const orderHashHex =
|
|
order.makerFeeAssetData === v2OrderId
|
|
? (await exchangeV2.getOrderInfo(order).callAsync()).orderHash
|
|
: orderHashUtils.getOrderHashHex(order);
|
|
const signature = `0x${signingUtils
|
|
.signMessage(ethUtil.toBuffer(orderHashHex), makerPrivateKey, SignatureType.EthSign)
|
|
.toString('hex')}`;
|
|
return {
|
|
...order,
|
|
signature,
|
|
};
|
|
}
|
|
|
|
describe('marketSellOrdersWithEth', () => {
|
|
it('should fill a single v2 order with no fees', async () => {
|
|
const order = await createOrderAsync({ makerFeeAssetData: v2OrderId });
|
|
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
|
|
.marketSellOrdersWithEth([order], [order.signature], [], [])
|
|
.callAsync({
|
|
from: takerAddress,
|
|
value: order.takerAssetAmount,
|
|
});
|
|
expect(wethSpentAmount).to.bignumber.eq(order.takerAssetAmount);
|
|
expect(makerAssetAcquiredAmount).to.bignumber.eq(order.makerAssetAmount);
|
|
});
|
|
it('should fill multiple v2 orders', async () => {
|
|
const orders = [
|
|
await createOrderAsync({ makerFeeAssetData: v2OrderId }),
|
|
await createOrderAsync({ makerFeeAssetData: v2OrderId }),
|
|
];
|
|
const ethSellAmount = BigNumber.sum(
|
|
orders[0].takerAssetAmount,
|
|
orders[1].takerAssetAmount.dividedToIntegerBy(2),
|
|
);
|
|
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
|
|
.marketSellOrdersWithEth(orders, orders.map(o => o.signature), [], [])
|
|
.callAsync({
|
|
from: takerAddress,
|
|
value: ethSellAmount,
|
|
});
|
|
expect(wethSpentAmount).to.bignumber.eq(ethSellAmount);
|
|
expect(makerAssetAcquiredAmount).to.bignumber.eq(
|
|
BigNumber.sum(orders[0].makerAssetAmount, orders[1].makerAssetAmount.dividedToIntegerBy(2)),
|
|
);
|
|
});
|
|
it.skip('should fill multiple v2/v3 orders', async () => {
|
|
const v2Order = await createOrderAsync({ makerFeeAssetData: v2OrderId });
|
|
const v3Order = await createOrderAsync();
|
|
const protocolFee = new BigNumber(150000).times(constants.DEFAULT_GAS_PRICE);
|
|
const ethSellAmount = BigNumber.sum(
|
|
v2Order.takerAssetAmount,
|
|
v3Order.takerAssetAmount.dividedToIntegerBy(2),
|
|
);
|
|
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
|
|
.marketSellOrdersWithEth([v2Order, v3Order], [v2Order.signature, v3Order.signature], [], [])
|
|
.callAsync({
|
|
from: takerAddress,
|
|
value: ethSellAmount.plus(protocolFee),
|
|
gasPrice: constants.DEFAULT_GAS_PRICE,
|
|
});
|
|
expect(wethSpentAmount).to.bignumber.eq(ethSellAmount.plus(protocolFee));
|
|
expect(makerAssetAcquiredAmount).to.bignumber.eq(
|
|
BigNumber.sum(v2Order.makerAssetAmount, v3Order.makerAssetAmount.dividedToIntegerBy(2)),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('marketBuyOrdersWithEth', () => {
|
|
it('should fill a single v2 order', async () => {
|
|
const order = await createOrderAsync({ makerFeeAssetData: v2OrderId });
|
|
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
|
|
.marketBuyOrdersWithEth([order], order.makerAssetAmount, [order.signature], [], [])
|
|
.callAsync({ from: takerAddress, value: order.takerAssetAmount });
|
|
expect(wethSpentAmount).to.bignumber.eq(order.takerAssetAmount);
|
|
expect(makerAssetAcquiredAmount).to.bignumber.eq(order.makerAssetAmount);
|
|
});
|
|
it('should fill multiple v2 orders', async () => {
|
|
const orders = [
|
|
await createOrderAsync({ makerFeeAssetData: v2OrderId }),
|
|
await createOrderAsync({ makerFeeAssetData: v2OrderId }),
|
|
];
|
|
const ethSellAmount = BigNumber.sum(
|
|
orders[0].takerAssetAmount,
|
|
orders[1].takerAssetAmount.dividedToIntegerBy(2),
|
|
);
|
|
const makerAssetBuyAmount = BigNumber.sum(
|
|
orders[0].makerAssetAmount,
|
|
orders[1].makerAssetAmount.dividedToIntegerBy(2),
|
|
);
|
|
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
|
|
.marketBuyOrdersWithEth(orders, makerAssetBuyAmount, orders.map(o => o.signature), [], [])
|
|
.callAsync({
|
|
from: takerAddress,
|
|
value: ethSellAmount,
|
|
});
|
|
expect(wethSpentAmount).to.bignumber.eq(ethSellAmount);
|
|
expect(makerAssetAcquiredAmount).to.bignumber.eq(makerAssetBuyAmount);
|
|
});
|
|
it.skip('should fill multiple v2/v3 orders', async () => {
|
|
const v2Order = await createOrderAsync({ makerFeeAssetData: v2OrderId });
|
|
const v3Order = await createOrderAsync();
|
|
const protocolFee = new BigNumber(150000).times(constants.DEFAULT_GAS_PRICE);
|
|
const ethSellAmount = BigNumber.sum(
|
|
v2Order.takerAssetAmount,
|
|
v3Order.takerAssetAmount.dividedToIntegerBy(2),
|
|
);
|
|
const makerAssetBuyAmount = BigNumber.sum(
|
|
v2Order.makerAssetAmount,
|
|
v3Order.makerAssetAmount.dividedToIntegerBy(2),
|
|
);
|
|
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
|
|
.marketBuyOrdersWithEth(
|
|
[v2Order, v3Order],
|
|
makerAssetBuyAmount,
|
|
[v2Order.signature, v3Order.signature],
|
|
[],
|
|
[],
|
|
)
|
|
.callAsync({
|
|
from: takerAddress,
|
|
value: ethSellAmount.plus(protocolFee),
|
|
gasPrice: constants.DEFAULT_GAS_PRICE,
|
|
});
|
|
expect(wethSpentAmount).to.bignumber.eq(ethSellAmount.plus(protocolFee));
|
|
expect(makerAssetAcquiredAmount).to.bignumber.eq(makerAssetBuyAmount);
|
|
});
|
|
});
|
|
});
|