add tests for LiquidityProviderFeature
This commit is contained in:
@@ -75,6 +75,7 @@ import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json
|
||||
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
|
||||
import * as SignatureValidatorFeature from '../test/generated-artifacts/SignatureValidatorFeature.json';
|
||||
import * as SimpleFunctionRegistryFeature from '../test/generated-artifacts/SimpleFunctionRegistryFeature.json';
|
||||
import * as TestBridge from '../test/generated-artifacts/TestBridge.json';
|
||||
import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json';
|
||||
import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCaller.json';
|
||||
import * as TestFillQuoteTransformerBridge from '../test/generated-artifacts/TestFillQuoteTransformerBridge.json';
|
||||
@@ -182,6 +183,7 @@ export const artifacts = {
|
||||
IExchange: IExchange as ContractArtifact,
|
||||
IGasToken: IGasToken as ContractArtifact,
|
||||
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
|
||||
TestBridge: TestBridge as ContractArtifact,
|
||||
TestCallTarget: TestCallTarget as ContractArtifact,
|
||||
TestDelegateCaller: TestDelegateCaller as ContractArtifact,
|
||||
TestFillQuoteTransformerBridge: TestFillQuoteTransformerBridge as ContractArtifact,
|
||||
|
@@ -1,26 +1,28 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils, StringRevertError, ZeroExRevertErrors } from '@0x/utils';
|
||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils';
|
||||
|
||||
import { IZeroExContract, TokenSpenderFeatureContract } from '../../src/wrappers';
|
||||
import {
|
||||
IOwnableFeatureContract,
|
||||
IZeroExContract,
|
||||
LiquidityProviderFeatureContract,
|
||||
TokenSpenderFeatureContract,
|
||||
} from '../../src/wrappers';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { abis } from '../utils/abis';
|
||||
import { fullMigrateAsync } from '../utils/migration';
|
||||
import { TestTokenSpenderERC20TokenContract, TestTokenSpenderERC20TokenEvents } from '../wrappers';
|
||||
import { IERC20BridgeEvents, TestBridgeContract, TestWethContract } from '../wrappers';
|
||||
|
||||
blockchainTests.resets('LiquidityProvider feature', env => {
|
||||
blockchainTests('LiquidityProvider feature', env => {
|
||||
let zeroEx: IZeroExContract;
|
||||
let feature: TokenSpenderFeatureContract;
|
||||
let token: TestTokenSpenderERC20TokenContract;
|
||||
let allowanceTarget: string;
|
||||
let feature: LiquidityProviderFeatureContract;
|
||||
let token: DummyERC20TokenContract;
|
||||
let weth: TestWethContract;
|
||||
let owner: string;
|
||||
let taker: string;
|
||||
|
||||
before(async () => {
|
||||
const [owner] = await env.getAccountAddressesAsync();
|
||||
[owner, taker] = await env.getAccountAddressesAsync();
|
||||
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {
|
||||
tokenSpender: (await TokenSpenderFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestTokenSpender,
|
||||
@@ -29,20 +31,220 @@ blockchainTests.resets('LiquidityProvider feature', env => {
|
||||
artifacts,
|
||||
)).address,
|
||||
});
|
||||
feature = new TokenSpenderFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis);
|
||||
token = await TestTokenSpenderERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestTokenSpenderERC20Token,
|
||||
const tokenSpender = new TokenSpenderFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis);
|
||||
const allowanceTarget = await tokenSpender.getAllowanceTarget().callAsync();
|
||||
|
||||
token = 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 token.setBalance(taker, constants.INITIAL_ERC20_BALANCE).awaitTransactionSuccessAsync();
|
||||
weth = await TestWethContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestWeth,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
allowanceTarget = await feature.getAllowanceTarget().callAsync();
|
||||
});
|
||||
await token
|
||||
.approve(allowanceTarget, constants.INITIAL_ERC20_ALLOWANCE)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
|
||||
feature = new LiquidityProviderFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis);
|
||||
const featureImpl = await LiquidityProviderFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.LiquidityProviderFeature,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
weth.address,
|
||||
);
|
||||
await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis)
|
||||
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
describe('Registry', () => {
|
||||
|
||||
it('`getLiquidityProviderForMarket` reverts if address is not set', async () => {
|
||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
||||
let tx = feature.getLiquidityProviderForMarket(xAsset, yAsset).awaitTransactionSuccessAsync();
|
||||
expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
||||
);
|
||||
tx = feature.getLiquidityProviderForMarket(yAsset, xAsset).awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(yAsset, xAsset),
|
||||
);
|
||||
});
|
||||
it('can set/get a liquidity provider address for a given market', async () => {
|
||||
const expectedAddress = randomAddress();
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, expectedAddress)
|
||||
.awaitTransactionSuccessAsync();
|
||||
let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
});
|
||||
it('can update a liquidity provider address for a given market', async () => {
|
||||
const expectedAddress = randomAddress();
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, expectedAddress)
|
||||
.awaitTransactionSuccessAsync();
|
||||
let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync();
|
||||
expect(actualAddress).to.equal(expectedAddress);
|
||||
});
|
||||
it('can effectively remove a liquidity provider for a market by setting the address to 0', async () => {
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, constants.NULL_ADDRESS)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const tx = feature
|
||||
.getLiquidityProviderForMarket(token.address, weth.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(token.address, weth.address),
|
||||
);
|
||||
});
|
||||
it('reverts if non-owner attempts to set an address', async () => {
|
||||
const tx = feature
|
||||
.setLiquidityProviderForMarket(randomAddress(), randomAddress(), randomAddress())
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker, owner));
|
||||
});
|
||||
});
|
||||
describe('Swap', () => {
|
||||
blockchainTests.resets('Swap', () => {
|
||||
let liquidityProvider: TestBridgeContract;
|
||||
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
||||
|
||||
before(async () => {
|
||||
liquidityProvider = await TestBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
token.address,
|
||||
weth.address,
|
||||
);
|
||||
await feature
|
||||
.setLiquidityProviderForMarket(token.address, weth.address, liquidityProvider.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
it('Cannot execute a swap for a market without a liquidity provider set', async () => {
|
||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
||||
const tx = feature
|
||||
.sellToLiquidityProvider(
|
||||
xAsset,
|
||||
yAsset,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ERC20-ERC20 swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
weth.address,
|
||||
token.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
inputToken: token.address,
|
||||
outputToken: weth.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: taker,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
);
|
||||
});
|
||||
it('Reverts if cannot fulfill the minimum buy amount', async () => {
|
||||
const minBuyAmount = new BigNumber(1);
|
||||
const tx = feature
|
||||
.sellToLiquidityProvider(
|
||||
weth.address,
|
||||
token.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
minBuyAmount,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.LiquidityProviderIncompleteSellError(
|
||||
liquidityProvider.address,
|
||||
weth.address,
|
||||
token.address,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
minBuyAmount,
|
||||
),
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ETH-ERC20 swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
token.address,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker, value: constants.ONE_ETHER });
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
inputToken: weth.address,
|
||||
outputToken: token.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: taker,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ERC20-ETH swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
ETH_TOKEN_ADDRESS,
|
||||
token.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
inputToken: token.address,
|
||||
outputToken: weth.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: zeroEx.address,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -73,6 +73,7 @@ export * from '../test/generated-wrappers/ownable_feature';
|
||||
export * from '../test/generated-wrappers/pay_taker_transformer';
|
||||
export * from '../test/generated-wrappers/signature_validator_feature';
|
||||
export * from '../test/generated-wrappers/simple_function_registry_feature';
|
||||
export * from '../test/generated-wrappers/test_bridge';
|
||||
export * from '../test/generated-wrappers/test_call_target';
|
||||
export * from '../test/generated-wrappers/test_delegate_caller';
|
||||
export * from '../test/generated-wrappers/test_fill_quote_transformer_bridge';
|
||||
|
Reference in New Issue
Block a user