* `@0x/contracts-zero-ex`: add limit orders feature `@0x/contracts-utils`: add `uint128` functions to `LibSafeMathV06` * `@0x/contract-addresses`: Update ganache snapshot addresses * `@0x/contracts-zero-ex`: Mask EIP712 struct hash values. * `@0x/contracts-zero-ex`: Add more limit order tests * `@0x/contracts-zero-ex`: Fix typos * `@0x/contracts-zero-ex`: Compute fee collector address after protocol fee zero check. * `@0x/contracts-zero-ex`: Remove WETH payment logic from fee collector fixin * `@0x/contracts-zero-ex`: Convert all ETH to WETH in `FeeCollector`. * `@0x/contracts-zero-ex`: Address review feedback * `@0x/contracts-zero-ex`: Export more utils * `@0x/contracts-zero-ex`: Rename `LimitOrdersFeatures`, `LibLimitOrders`, etc. into `*NativeOrders*`. `@0x/contracts-zero-ex`: Emit `protocolFeePaid` in native order fill events. `@0x/contracts-zero-ex`: Refactor to get around stack limits. `@0x/contracts-zero-ex`: Use different storage mappings for RFQ and limit order pair cancellations. * `@0x/contracts-zero-ex`: Add `getProtocolFeeMultiplier()` and `transferProtocolFeesForPools()` to `NativeOrdersFeature`. * `@0x/contracts-zero-ex`: Fix broken tests * update orders docs * `@0x/contracts-zero-ex`: Add more tests to `NativeOrdersFeature` * rebuild after rebase * `@0x/contract-addresses`: Fix changelog booboo * `@0x/contracts-zero-ex`: Add method selectors output to generated artifacts * `@0x/contracts-zero-ex`: Add maker address to order cancel events. `@0x/contracts-zreo-ex`: Remove `UpTo` suffix from order pair cancellation functions. `@0x/contracts-zreo-ex`: Address misc review comments. * `@0x/contracts-zero-ex`: More SafeMath in native orders * update orders docs Co-authored-by: Lawrence Forman <me@merklejerk.com>
135 lines
6.4 KiB
TypeScript
135 lines
6.4 KiB
TypeScript
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
|
import { AuthorizableRevertErrors, BigNumber, hexUtils } from '@0x/utils';
|
|
|
|
import { artifacts } from './artifacts';
|
|
import { FeeCollectorContract, TestFixinProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
|
|
|
|
blockchainTests.resets('ProtocolFees', env => {
|
|
const FEE_MULTIPLIER = 70e3;
|
|
let taker: string;
|
|
let unauthorized: string;
|
|
let protocolFees: TestFixinProtocolFeesContract;
|
|
let staking: TestStakingContract;
|
|
let weth: TestWethContract;
|
|
let singleFeeAmount: BigNumber;
|
|
|
|
before(async () => {
|
|
[taker, unauthorized] = await env.getAccountAddressesAsync();
|
|
weth = await TestWethContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestWeth,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
staking = await TestStakingContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestStaking,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
weth.address,
|
|
);
|
|
protocolFees = await TestFixinProtocolFeesContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestFixinProtocolFees,
|
|
env.provider,
|
|
{ ...env.txDefaults, from: taker },
|
|
artifacts,
|
|
weth.address,
|
|
staking.address,
|
|
FEE_MULTIPLIER,
|
|
);
|
|
singleFeeAmount = await protocolFees.getSingleProtocolFee().callAsync();
|
|
await weth.mint(taker, singleFeeAmount).awaitTransactionSuccessAsync();
|
|
await weth.approve(protocolFees.address, singleFeeAmount).awaitTransactionSuccessAsync({ from: taker });
|
|
});
|
|
|
|
describe('FeeCollector', () => {
|
|
it('should disallow unauthorized initialization', async () => {
|
|
const pool = hexUtils.random();
|
|
|
|
await protocolFees.collectProtocolFee(pool).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
|
await protocolFees.transferFeesForPool(pool).awaitTransactionSuccessAsync();
|
|
|
|
const feeCollector = new FeeCollectorContract(
|
|
await protocolFees.getFeeCollector(pool).callAsync(),
|
|
env.provider,
|
|
env.txDefaults,
|
|
);
|
|
|
|
const tx = feeCollector
|
|
.initialize(weth.address, staking.address, pool)
|
|
.sendTransactionAsync({ from: unauthorized });
|
|
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(unauthorized));
|
|
});
|
|
});
|
|
|
|
describe('_collectProtocolFee()', () => {
|
|
const pool1 = hexUtils.random();
|
|
const pool2 = hexUtils.random();
|
|
let feeCollector1Address: string;
|
|
let feeCollector2Address: string;
|
|
|
|
before(async () => {
|
|
feeCollector1Address = await protocolFees.getFeeCollector(pool1).callAsync();
|
|
feeCollector2Address = await protocolFees.getFeeCollector(pool2).callAsync();
|
|
});
|
|
|
|
it('should revert if insufficient ETH transferred', async () => {
|
|
const tooLittle = singleFeeAmount.minus(1);
|
|
const tx = protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: tooLittle });
|
|
return expect(tx).to.revertWith('FixinProtocolFees/ETHER_TRANSFER_FALIED');
|
|
});
|
|
|
|
it('should accept ETH fee', async () => {
|
|
const beforeETH = await env.web3Wrapper.getBalanceInWeiAsync(taker);
|
|
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
|
const afterETH = await env.web3Wrapper.getBalanceInWeiAsync(taker);
|
|
|
|
// We check for greater than fee spent to allow for spending on gas.
|
|
await expect(beforeETH.minus(afterETH)).to.bignumber.gt(singleFeeAmount);
|
|
|
|
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector1Address)).to.bignumber.eq(
|
|
singleFeeAmount,
|
|
);
|
|
});
|
|
|
|
it('should accept ETH after first transfer', async () => {
|
|
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
|
await protocolFees.transferFeesForPool(pool1).awaitTransactionSuccessAsync();
|
|
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
|
await protocolFees.transferFeesForPool(pool1).awaitTransactionSuccessAsync();
|
|
|
|
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
|
|
|
|
// We leave 1 wei of WETH behind.
|
|
await expect(balanceWETH).to.bignumber.eq(singleFeeAmount.times(2).minus(1));
|
|
await expect(await weth.balanceOf(feeCollector1Address).callAsync()).to.bignumber.equal(1);
|
|
// And no ETH.
|
|
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector1Address)).to.bignumber.eq(0);
|
|
});
|
|
|
|
it('should attribute fees correctly', async () => {
|
|
await protocolFees.collectProtocolFee(pool1).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
|
await protocolFees.transferFeesForPool(pool1).awaitTransactionSuccessAsync();
|
|
await protocolFees.collectProtocolFee(pool2).awaitTransactionSuccessAsync({ value: singleFeeAmount });
|
|
await protocolFees.transferFeesForPool(pool2).awaitTransactionSuccessAsync();
|
|
|
|
const pool1Balance = await staking.balanceForPool(pool1).callAsync();
|
|
const pool2Balance = await staking.balanceForPool(pool2).callAsync();
|
|
|
|
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
|
|
|
|
await expect(balanceWETH).to.bignumber.equal(singleFeeAmount.times(2).minus(2));
|
|
|
|
// We leave 1 wei of WETH behind.
|
|
await expect(pool1Balance).to.bignumber.equal(singleFeeAmount.minus(1));
|
|
await expect(pool2Balance).to.bignumber.equal(singleFeeAmount.minus(1));
|
|
await expect(await weth.balanceOf(feeCollector1Address).callAsync()).to.bignumber.equal(1);
|
|
await expect(await weth.balanceOf(feeCollector2Address).callAsync()).to.bignumber.equal(1);
|
|
await expect(pool2Balance).to.bignumber.equal(singleFeeAmount.minus(1));
|
|
// And no ETH.
|
|
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector1Address)).to.bignumber.eq(0);
|
|
await expect(await env.web3Wrapper.getBalanceInWeiAsync(feeCollector2Address)).to.bignumber.eq(0);
|
|
});
|
|
});
|
|
});
|