@0x:contracts-integrations Wrote a simple integration test and AddressManager

This commit is contained in:
Alex Towle 2019-10-08 17:24:11 -07:00
parent 6cba9fd77f
commit 01aee08c02
7 changed files with 266 additions and 85 deletions

View File

@ -2,3 +2,4 @@ export * from './artifacts';
export * from './wrappers'; export * from './wrappers';
export * from '../test/utils/function_assertions'; export * from '../test/utils/function_assertions';
export * from '../test/utils/deployment_manager'; export * from '../test/utils/deployment_manager';
export * from '../test/utils/address_manager';

View File

@ -0,0 +1,138 @@
import { blockchainTests, constants, expect, filterLogsToArguments, OrderFactory } from '@0x/contracts-test-utils';
import { DummyERC20TokenContract, IERC20TokenEvents, IERC20TokenTransferEventArgs } from '@0x/contracts-erc20';
import { IExchangeEvents, IExchangeFillEventArgs } from '@0x/contracts-exchange';
import { IStakingEventsEvents, IStakingEventsStakingPoolActivatedEventArgs } from '@0x/contracts-staking';
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import { DeploymentManager, AddressManager } from '../../src';
blockchainTests('Exchange & Staking', async env => {
let accounts: string[];
let makerAddress: string;
let takers: string[];
let delegators: string[];
let feeRecipientAddress: string;
let addressManager: AddressManager;
let deploymentManager: DeploymentManager;
let orderFactory: OrderFactory;
let makerAsset: DummyERC20TokenContract;
let takerAsset: DummyERC20TokenContract;
let feeAsset: DummyERC20TokenContract;
const gasPrice = 1e9;
before(async () => {
const chainId = await env.getChainIdAsync();
accounts = await env.getAccountAddressesAsync();
makerAddress = accounts[1];
feeRecipientAddress = accounts[2];
takers = [accounts[3], accounts[4]];
delegators = [accounts[5], accounts[6], accounts[7]];
deploymentManager = await DeploymentManager.deployAsync(env);
// Create a staking pool with the operator as a maker address.
await deploymentManager.staking.stakingWrapper.createStakingPool.awaitTransactionSuccessAsync(
constants.ZERO_AMOUNT,
true,
{ from: makerAddress },
);
// Set up an address for market making.
addressManager = new AddressManager();
await addressManager.addMakerAsync(
deploymentManager,
{
address: makerAddress,
mainToken: deploymentManager.tokens.erc20[0],
feeToken: deploymentManager.tokens.erc20[2],
},
env,
deploymentManager.tokens.erc20[1],
feeRecipientAddress,
chainId,
);
// Set up two addresses for taking orders.
await addressManager.addTakersAsync(
deploymentManager,
takers.map(takerAddress => {
return {
address: takerAddress,
mainToken: deploymentManager.tokens.erc20[1],
feeToken: deploymentManager.tokens.erc20[2],
};
}),
);
});
describe('fillOrder', () => {
it('should be able to fill an order', async () => {
const order = await addressManager.makerAddresses[0].orderFactory.newSignedOrderAsync({
makerAddress,
makerAssetAmount: new BigNumber(1),
takerAssetAmount: new BigNumber(1),
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
feeRecipientAddress,
});
const receipt = await deploymentManager.exchange.fillOrder.awaitTransactionSuccessAsync(
order,
new BigNumber(1),
order.signature,
{
from: takers[0],
gasPrice,
value: DeploymentManager.protocolFeeMultiplier.times(gasPrice),
},
);
// Ensure that the number of emitted logs is equal to 3. There should have been a fill event
// and two transfer events. A 'StakingPoolActivated' event should not be expected because
// the only staking pool that was created does not have enough stake.
expect(receipt.logs.length).to.be.eq(3);
// Ensure that the fill event was correct.
const fillArgs = filterLogsToArguments<IExchangeFillEventArgs>(receipt.logs, IExchangeEvents.Fill);
expect(fillArgs.length).to.be.eq(1);
expect(fillArgs).to.be.deep.eq([
{
makerAddress,
feeRecipientAddress,
makerAssetData: order.makerAssetData,
takerAssetData: order.takerAssetData,
makerFeeAssetData: order.makerFeeAssetData,
takerFeeAssetData: order.takerFeeAssetData,
orderHash: orderHashUtils.getOrderHashHex(order),
takerAddress: takers[0],
senderAddress: takers[0],
makerAssetFilledAmount: order.makerAssetAmount,
takerAssetFilledAmount: order.takerAssetAmount,
makerFeePaid: constants.ZERO_AMOUNT,
takerFeePaid: constants.ZERO_AMOUNT,
protocolFeePaid: DeploymentManager.protocolFeeMultiplier.times(gasPrice),
},
]);
// Ensure that the transfer events were correctly emitted.
const transferArgs = filterLogsToArguments<IERC20TokenTransferEventArgs>(
receipt.logs,
IERC20TokenEvents.Transfer,
);
expect(transferArgs.length).to.be.eq(2);
expect(transferArgs).to.be.deep.eq([
{
_from: takers[0],
_to: makerAddress,
_value: order.takerAssetAmount,
},
{
_from: makerAddress,
_to: takers[0],
_value: order.makerAssetAmount,
},
]);
});
});
});

View File

@ -1,50 +0,0 @@
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
import { assetDataUtils } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import { DeploymentManager } from '../../src';
blockchainTests('Exchange & Staking', env => {
let accounts: string[];
let deploymentManager: DeploymentManager;
before(async () => {
accounts = await env.getAccountAddressesAsync();
deploymentManager = await DeploymentManager.deployAsync(env);
// Create a staking pool with the operator as a maker address.
await deploymentManager.staking.stakingWrapper.createStakingPool.awaitTransactionSuccessAsync(
constants.ZERO_AMOUNT,
true,
);
// TODO(jalextowle): I will eventually want these utilities to be in the deployment manager.
// Create default order parameters
// const defaultOrderParams = {
// ...constants.STATIC_ORDER_PARAMS,
// makerAddress: accounts[1],
// makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
// takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
// makerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultFeeTokenAddress),
// takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultFeeTokenAddress),
// feeRecipientAddress: feeRecipientAddressLeft,
// exchangeAddress: exchange.address,
// chainId,
// };
});
// Function assertions for all of the functions involved in
// (1) Creating a staking pool
// - At first, this can be isolated.
// (2) Joining a staking pool as a maker
// - This can be isolated too, and we can assume a limited number
// of market makers to make things easy.
// (3) Paying a protocol fee
// - I'm personally of the opinion that we should write integration
// tests for the exchange and the staking contracts to interoperate.
// (4) Going to the next epoch
// - This might be something that just get's called every certain number of itterations
// for simple tests.
// (5) Finalizing a pool in the epoch
// - Ditto
});

View File

@ -0,0 +1,122 @@
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { constants, OrderFactory, BlockchainTestsEnvironment } from '@0x/contracts-test-utils';
import { assetDataUtils, Order, SignatureType, SignedOrder } from '@0x/order-utils';
import { DeploymentManager } from '../../src';
interface MarketMaker {
address: string;
orderFactory: OrderFactory;
}
interface ConfigurationArgs {
address: string;
mainToken: DummyERC20TokenContract;
feeToken: DummyERC20TokenContract;
}
export class AddressManager {
// A set of addresses that have been configured for market making.
public makerAddresses: MarketMaker[];
// A set of addresses that have been configured to take orders.
public takerAddresses: string[];
/**
* Sets up an address to take orders.
*/
public async addTakerAsync(deploymentManager: DeploymentManager, configArgs: ConfigurationArgs): Promise<void> {
// Configure the taker address with the taker and fee tokens.
await this._configureTokenForAddressAsync(deploymentManager, configArgs.address, configArgs.mainToken);
await this._configureTokenForAddressAsync(deploymentManager, configArgs.address, configArgs.feeToken);
// Add the taker to the list of configured taker addresses.
this.takerAddresses.push(configArgs.address);
}
/**
* Sets up a list of addresses to take orders.
*/
public async addTakersAsync(deploymentManager: DeploymentManager, configArgs: ConfigurationArgs[]): Promise<void> {
for (const args of configArgs) {
await this.addTakerAsync(deploymentManager, args);
}
}
/**
* Sets up an address for market making.
*/
public async addMakerAsync(
deploymentManager: DeploymentManager,
configArgs: ConfigurationArgs,
environment: BlockchainTestsEnvironment,
takerToken: DummyERC20TokenContract,
feeRecipientAddress: string,
chainId: number,
): Promise<void> {
const accounts = await environment.getAccountAddressesAsync();
// Set up order signing for the maker address.
const defaultOrderParams = {
...constants.STATIC_ORDER_PARAMS,
makerAddress: configArgs.address,
makerAssetData: assetDataUtils.encodeERC20AssetData(configArgs.mainToken.address),
takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address),
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(configArgs.feeToken.address),
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(configArgs.feeToken.address),
feeRecipientAddress,
exchangeAddress: deploymentManager.exchange.address,
chainId,
};
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(configArgs.address)];
const orderFactory = new OrderFactory(privateKey, defaultOrderParams);
// Configure the maker address with the maker and fee tokens.
await this._configureTokenForAddressAsync(deploymentManager, configArgs.address, configArgs.mainToken);
await this._configureTokenForAddressAsync(deploymentManager, configArgs.address, configArgs.feeToken);
// Add the maker to the list of configured maker addresses.
this.makerAddresses.push({
address: configArgs.address,
orderFactory,
});
}
/**
* Sets up several market makers.
*/
public async addMakersAsync(
deploymentManager: DeploymentManager,
configArgs: ConfigurationArgs[],
environment: BlockchainTestsEnvironment,
takerToken: DummyERC20TokenContract,
feeRecipientAddress: string,
chainId: number,
): Promise<void> {
for (const args of configArgs) {
await this.addMakerAsync(deploymentManager, args, environment, takerToken, feeRecipientAddress, chainId);
}
}
/**
* Sets up initial account balances for a token and approves the ERC20 asset proxy
* to transfer the token.
*/
protected async _configureTokenForAddressAsync(
deploymentManager: DeploymentManager,
address: string,
token: DummyERC20TokenContract,
): Promise<void> {
await token.setBalance.awaitTransactionSuccessAsync(address, constants.INITIAL_ERC20_BALANCE);
await token.approve.awaitTransactionSuccessAsync(
deploymentManager.assetProxies.erc20Proxy.address,
constants.MAX_UINT256,
{ from: address },
);
}
constructor(makers?: MarketMaker[], takers?: string[]) {
this.makerAddresses = [];
this.takerAddresses = [];
}
}

View File

@ -34,11 +34,6 @@ import { BigNumber } from '@0x/utils';
import { TxData } from 'ethereum-types'; import { TxData } from 'ethereum-types';
import * as _ from 'lodash'; import * as _ from 'lodash';
<<<<<<< HEAD:contracts/integrations/test/deployment/deployment_mananger.ts
=======
import { artifacts, TestStakingPlaceholderContract } from '../../src';
>>>>>>> `@0x/contracts-integrations` Created the FunctionAssertion class and examples:contracts/integrations/test/utils/deployment_mananger.ts
/** /**
* Adds a batch of authorities to a list of authorizable contracts. * Adds a batch of authorities to a list of authorizable contracts.
* @param owner The owner of the authorizable contracts. * @param owner The owner of the authorizable contracts.
@ -111,15 +106,9 @@ interface StakingContracts {
// Contract wrappers for tokens. // Contract wrappers for tokens.
interface TokenContracts { interface TokenContracts {
<<<<<<< HEAD:contracts/integrations/test/deployment/deployment_mananger.ts
erc20: DummyERC20TokenContract[]; erc20: DummyERC20TokenContract[];
erc721: DummyERC721TokenContract[]; erc721: DummyERC721TokenContract[];
erc1155: ERC1155MintableContract[]; erc1155: ERC1155MintableContract[];
=======
erc1155: ERC1155Contract;
erc20: ERC20TokenContract[];
erc721: ERC721TokenContract;
>>>>>>> `@0x/contracts-integrations` Created the FunctionAssertion class and examples:contracts/integrations/test/utils/deployment_mananger.ts
weth: WETH9Contract; weth: WETH9Contract;
zrx: ZRXTokenContract; zrx: ZRXTokenContract;
} }
@ -160,7 +149,7 @@ export class DeploymentManager {
exchangeArtifacts.Exchange, exchangeArtifacts.Exchange,
environment.provider, environment.provider,
environment.txDefaults, environment.txDefaults,
exchangeArtifacts, { ...ERC20Artifacts, ...exchangeArtifacts },
new BigNumber(chainId), new BigNumber(chainId),
); );
const governor = await ZeroExGovernorContract.deployFrom0xArtifactAsync( const governor = await ZeroExGovernorContract.deployFrom0xArtifactAsync(
@ -418,7 +407,6 @@ export class DeploymentManager {
txDefaults: Partial<TxData>, txDefaults: Partial<TxData>,
options: Partial<DeploymentOptions>, options: Partial<DeploymentOptions>,
): Promise<TokenContracts> { ): Promise<TokenContracts> {
<<<<<<< HEAD:contracts/integrations/test/deployment/deployment_mananger.ts
const numErc20TokensToDeploy = const numErc20TokensToDeploy =
options.numErc20TokensToDeploy !== undefined options.numErc20TokensToDeploy !== undefined
? options.numErc20TokensToDeploy ? options.numErc20TokensToDeploy
@ -447,26 +435,6 @@ export class DeploymentManager {
constants.DUMMY_TOKEN_TOTAL_SUPPLY, constants.DUMMY_TOKEN_TOTAL_SUPPLY,
), ),
), ),
=======
const erc20 = [];
erc20[0] = await ERC20TokenContract.deployFrom0xArtifactAsync(
ERC20Artifacts.ERC20Token,
environment.provider,
txDefaults,
ERC20Artifacts,
);
erc20[1] = await ERC20TokenContract.deployFrom0xArtifactAsync(
ERC20Artifacts.ERC20Token,
environment.provider,
txDefaults,
ERC20Artifacts,
);
erc20[2] = await ERC20TokenContract.deployFrom0xArtifactAsync(
ERC20Artifacts.ERC20Token,
environment.provider,
txDefaults,
ERC20Artifacts,
>>>>>>> `@0x/contracts-integrations` Created the FunctionAssertion class and examples:contracts/integrations/test/utils/deployment_mananger.ts
); );
const erc721 = await Promise.all( const erc721 = await Promise.all(
_.times( _.times(

View File

@ -9,10 +9,12 @@ import { signingUtils } from './signing_utils';
export class OrderFactory { export class OrderFactory {
private readonly _defaultOrderParams: Partial<Order>; private readonly _defaultOrderParams: Partial<Order>;
private readonly _privateKey: Buffer; private readonly _privateKey: Buffer;
constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) { constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) {
this._defaultOrderParams = defaultOrderParams; this._defaultOrderParams = defaultOrderParams;
this._privateKey = privateKey; this._privateKey = privateKey;
} }
public async newSignedOrderAsync( public async newSignedOrderAsync(
customOrderParams: Partial<Order> = {}, customOrderParams: Partial<Order> = {},
signatureType: SignatureType = SignatureType.EthSign, signatureType: SignatureType = SignatureType.EthSign,