protocol/contracts/integrations/test/stop-limit/chainlink_stop_limit_test.ts
mzhu25 dcce8276b8
Add decoders for broker and stop-limit data (#2484)
* Add decoders for broker and stop-limit data

* update changelogs

* Address comments
2020-02-14 17:38:43 -08:00

193 lines
8.0 KiB
TypeScript

import { ExchangeRevertErrors } from '@0x/contracts-exchange';
import {
blockchainTests,
constants,
expect,
getRandomInteger,
orderHashUtils,
randomAddress,
} from '@0x/contracts-test-utils';
import { assetDataUtils } from '@0x/order-utils';
import { SignedOrder } from '@0x/types';
import { BigNumber, StringRevertError } from '@0x/utils';
import {
decodeChainlinkStopLimitData,
decodeStopLimitStaticCallData,
encodeChainlinkStopLimitData,
encodeStopLimitStaticCallData,
} from '../../src/chainlink_utils';
import { artifacts } from '../artifacts';
import { Actor } from '../framework/actors/base';
import { Maker } from '../framework/actors/maker';
import { Taker } from '../framework/actors/taker';
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
import { LocalBalanceStore } from '../framework/balances/local_balance_store';
import { DeploymentManager } from '../framework/deployment_manager';
import { ChainlinkStopLimitContract, TestChainlinkAggregatorContract } from '../wrappers';
blockchainTests.resets('Chainlink stop-limit order tests', env => {
let deployment: DeploymentManager;
let balanceStore: BlockchainBalanceStore;
let initialBalances: LocalBalanceStore;
let chainLinkAggregator: TestChainlinkAggregatorContract;
let chainlinkStopLimit: ChainlinkStopLimitContract;
let maker: Maker;
let taker: Taker;
let order: SignedOrder;
const minPrice = new BigNumber(42);
const maxPrice = new BigNumber(1337);
before(async () => {
deployment = await DeploymentManager.deployAsync(env, {
numErc20TokensToDeploy: 2,
numErc721TokensToDeploy: 0,
numErc1155TokensToDeploy: 0,
});
const [makerToken, takerToken] = deployment.tokens.erc20;
chainlinkStopLimit = await ChainlinkStopLimitContract.deployFrom0xArtifactAsync(
artifacts.ChainlinkStopLimit,
env.provider,
env.txDefaults,
artifacts,
);
chainLinkAggregator = await TestChainlinkAggregatorContract.deployFrom0xArtifactAsync(
artifacts.TestChainlinkAggregator,
env.provider,
env.txDefaults,
artifacts,
);
const makerAssetData = assetDataUtils.encodeMultiAssetData(
[new BigNumber(1), new BigNumber(1)],
[
assetDataUtils.encodeERC20AssetData(makerToken.address),
encodeStopLimitStaticCallData(chainlinkStopLimit.address, {
oracle: chainLinkAggregator.address,
minPrice,
maxPrice,
}),
],
);
const orderConfig = {
feeRecipientAddress: constants.NULL_ADDRESS,
makerAssetData,
takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address),
makerFeeAssetData: constants.NULL_BYTES,
takerFeeAssetData: constants.NULL_BYTES,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
};
maker = new Maker({
name: 'Maker',
deployment,
orderConfig,
});
taker = new Taker({ name: 'Taker', deployment });
// Set balances and allowances
await maker.configureERC20TokenAsync(makerToken);
await taker.configureERC20TokenAsync(takerToken);
order = await maker.signOrderAsync();
// Set up balance stores
const tokenOwners = {
Maker: maker.address,
Taker: taker.address,
};
const tokenContracts = {
erc20: { makerToken, takerToken },
};
balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts);
await balanceStore.updateBalancesAsync();
initialBalances = LocalBalanceStore.create(balanceStore);
});
after(async () => {
Actor.reset();
});
describe('filling stop-limit orders', () => {
it('fillOrder reverts if price < minPrice', async () => {
await chainLinkAggregator.setPrice(minPrice.minus(1)).awaitTransactionSuccessAsync();
const tx = taker.fillOrderAsync(order, order.takerAssetAmount);
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
orderHashUtils.getOrderHashHex(order),
order.makerAssetData,
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
);
return expect(tx).to.revertWith(expectedError);
});
it('fillOrder reverts price > maxPrice', async () => {
await chainLinkAggregator.setPrice(maxPrice.plus(1)).awaitTransactionSuccessAsync();
const tx = taker.fillOrderAsync(order, order.takerAssetAmount);
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
orderHashUtils.getOrderHashHex(order),
order.makerAssetData,
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
);
return expect(tx).to.revertWith(expectedError);
});
it('fillOrder succeeds if price = minPrice', async () => {
await chainLinkAggregator.setPrice(minPrice).awaitTransactionSuccessAsync();
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
const expectedBalances = LocalBalanceStore.create(initialBalances);
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
await balanceStore.updateBalancesAsync();
balanceStore.assertEquals(expectedBalances);
});
it('fillOrder succeeds if price = maxPrice', async () => {
await chainLinkAggregator.setPrice(maxPrice).awaitTransactionSuccessAsync();
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
const expectedBalances = LocalBalanceStore.create(initialBalances);
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
await balanceStore.updateBalancesAsync();
balanceStore.assertEquals(expectedBalances);
});
it('fillOrder succeeds if minPrice < price < maxPrice', async () => {
await chainLinkAggregator
.setPrice(minPrice.plus(maxPrice).dividedToIntegerBy(2))
.awaitTransactionSuccessAsync();
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
const expectedBalances = LocalBalanceStore.create(initialBalances);
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
await balanceStore.updateBalancesAsync();
balanceStore.assertEquals(expectedBalances);
});
});
describe('Data encoding/decoding tools', () => {
const MAX_INT256 = new BigNumber(2).exponentiatedBy(255).minus(1);
it('correctly decodes chainlink stop-limit params', async () => {
const params = {
oracle: randomAddress(),
minPrice: getRandomInteger(0, MAX_INT256),
maxPrice: getRandomInteger(0, MAX_INT256),
};
const encoded = encodeChainlinkStopLimitData(params);
const decoded = decodeChainlinkStopLimitData(encoded);
expect(decoded).to.deep.equal(params);
});
it('correctly decodes stop-limit assetData', async () => {
const params = {
oracle: randomAddress(),
minPrice: getRandomInteger(0, MAX_INT256),
maxPrice: getRandomInteger(0, MAX_INT256),
};
const encoded = encodeStopLimitStaticCallData(chainlinkStopLimit.address, params);
const decoded = decodeStopLimitStaticCallData(encoded);
expect(decoded).to.deep.equal(params);
});
});
});