239 lines
9.2 KiB
TypeScript
239 lines
9.2 KiB
TypeScript
import { blockchainTests, constants } from '@0x/contracts-test-utils';
|
|
import { BigNumber } from '@0x/utils';
|
|
|
|
import { artifacts, TestProtocolFeesContract, TestProtocolFeesERC20ProxyContract } from '../src';
|
|
|
|
import { ProtocolFeeActor } from './actors/protocol_fee_actor';
|
|
|
|
// tslint:disable:no-unnecessary-type-assertion
|
|
blockchainTests('Protocol Fee Unit Tests', env => {
|
|
// The accounts that will be used during testing.
|
|
let owner: string;
|
|
let exchange: string;
|
|
let nonExchange: string;
|
|
let makerAddress: string;
|
|
let payerAddress: string;
|
|
|
|
// The actor that will be used for testng `payProtocolFee` and `_unwrapETH`.
|
|
let protocolFeeActor: ProtocolFeeActor;
|
|
|
|
// The default protocol fee that will be paid -- a somewhat realistic value.
|
|
const DEFAULT_PROTOCOL_FEE_PAID = new BigNumber(150000).times(10000000);
|
|
|
|
// The default pool Id that will be used.
|
|
const DEFAULT_POOL_ID = '0x0000000000000000000000000000000000000000000000000000000000000001';
|
|
|
|
before(async () => {
|
|
// Get accounts to represent the exchange and an address that is not a registered exchange.
|
|
[
|
|
owner,
|
|
exchange,
|
|
nonExchange,
|
|
makerAddress,
|
|
payerAddress,
|
|
] = (await env.web3Wrapper.getAvailableAddressesAsync()).slice(0, 6);
|
|
|
|
// Deploy the protocol fees contract.
|
|
const protocolFees = await TestProtocolFeesContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestProtocolFees,
|
|
env.provider,
|
|
{
|
|
...env.txDefaults,
|
|
from: owner,
|
|
},
|
|
artifacts,
|
|
);
|
|
|
|
// Deploy the erc20Proxy for testing.
|
|
const proxy = await TestProtocolFeesERC20ProxyContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestProtocolFeesERC20Proxy,
|
|
env.provider,
|
|
env.txDefaults,
|
|
{},
|
|
);
|
|
|
|
// Register the test ERC20Proxy in the exchange.
|
|
await protocolFees.setWethProxy.awaitTransactionSuccessAsync(proxy.address);
|
|
|
|
// Register an exchange in the protocol fee contract.
|
|
await protocolFees.addExchangeAddress.awaitTransactionSuccessAsync(exchange, { from: owner });
|
|
|
|
// "Register" the makerAddress in the default pool.
|
|
await protocolFees.addMakerToPool.awaitTransactionSuccessAsync(DEFAULT_POOL_ID, makerAddress);
|
|
|
|
// Initialize the protocol fee actor.
|
|
protocolFeeActor = new ProtocolFeeActor([exchange], [makerAddress], protocolFees);
|
|
});
|
|
|
|
blockchainTests.resets('payProtocolFee', () => {
|
|
it('should revert if called by a non-exchange', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: nonExchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
});
|
|
|
|
it('should revert if `protocolFeePaid` is zero with zero value sent', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: constants.ZERO_AMOUNT,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
});
|
|
|
|
it('should revert if `protocolFeePaid` is zero with non-zero value sent', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: constants.ZERO_AMOUNT,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
});
|
|
|
|
it('should revert if `protocolFeePaid` is different than the provided message value', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID.minus(50),
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
});
|
|
|
|
it('should call `transferFrom` in the proxy if no value is sent and the maker is not in a pool', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress: payerAddress, // This is an unregistered maker address
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
});
|
|
|
|
it('should call `transferFrom` in the proxy and update `protocolFeesThisEpochByPool` if no value is sent and the maker is in a pool', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
});
|
|
|
|
it('should not call `transferFrom` in the proxy and should not update `protocolFeesThisEpochByPool` if value is sent and the maker is not in a pool', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress: payerAddress, // This is an unregistered maker address
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
});
|
|
|
|
it('should not call `transferFrom` in the proxy and should update `protocolFeesThisEpochByPool` if value is sent and the maker is in a pool', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
});
|
|
|
|
it('should only have one active pool if a fee is paid on behalf of one maker ETH twice', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
});
|
|
|
|
it('should only have one active pool if a fee is paid on behalf of one maker in WETH and then ETH', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
});
|
|
|
|
it('should only have one active pool if a fee is paid on behalf of one maker in ETH and then WETH', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: DEFAULT_PROTOCOL_FEE_PAID,
|
|
});
|
|
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
});
|
|
|
|
it('should only have one active pool if a fee is paid on behalf of one maker in WETH twice', async () => {
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
|
|
await protocolFeeActor.payProtocolFeeAsync({
|
|
poolId: DEFAULT_POOL_ID,
|
|
makerAddress,
|
|
payerAddress,
|
|
protocolFeePaid: DEFAULT_PROTOCOL_FEE_PAID,
|
|
from: exchange,
|
|
value: constants.ZERO_AMOUNT,
|
|
});
|
|
});
|
|
});
|
|
});
|
|
// tslint:enable:no-unnecessary-type-assertion
|