Add forwarder mainnet tests
This commit is contained in:
201
contracts/integrations/test/forwarder/forwarder_mainnet_test.ts
Normal file
201
contracts/integrations/test/forwarder/forwarder_mainnet_test.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
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(new BigNumber(2), 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
22
contracts/integrations/test/forwarder/types.ts
Normal file
22
contracts/integrations/test/forwarder/types.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
export interface V2Order {
|
||||
makerAddress: string;
|
||||
takerAddress: string;
|
||||
senderAddress: string;
|
||||
feeRecipientAddress: string;
|
||||
makerAssetAmount: BigNumber;
|
||||
takerAssetAmount: BigNumber;
|
||||
makerFee: BigNumber;
|
||||
takerFee: BigNumber;
|
||||
salt: BigNumber;
|
||||
expirationTimeSeconds: BigNumber;
|
||||
makerAssetData: string;
|
||||
takerAssetData: string;
|
||||
makerFeeAssetData: string;
|
||||
takerFeeAssetData: string;
|
||||
}
|
||||
|
||||
export interface SignedV2Order extends V2Order {
|
||||
signature: string;
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"exchange": "0x61935cbdd02287b511119ddb11aeb42f1593b7ef",
|
||||
"erc20Proxy": "0x95e6f48254609a6ee006f7d493c8e5fb97094cef",
|
||||
"erc721Proxy": "0xefc70a1b18c432bdc64b596838b4d138f6bc6cad",
|
||||
"forwarder": "0xbf1e3a8405906904b3692446e0fb4e309628a9fe",
|
||||
"forwarder": "0x9ea309d4f96d6433c75a6b9c5a596cf19a87edb8",
|
||||
"orderValidator": "0x0000000000000000000000000000000000000000",
|
||||
"zrxToken": "0xe41d2489571d322189246dafa5ebde1f4699f498",
|
||||
"etherToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
|
||||
Reference in New Issue
Block a user