parent
afd4805421
commit
75dcd687e2
@ -1,17 +1,19 @@
|
||||
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { AuthorizableRevertErrors, BigNumber, hexUtils, ZeroExRevertErrors } from '@0x/utils';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
|
||||
import { FeeCollectorContract, TestProtocolFeesContract, TestStakingContract, TestWethContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('ProtocolFees', env => {
|
||||
let payer: string;
|
||||
let unauthorized: string;
|
||||
let protocolFees: TestProtocolFeesContract;
|
||||
let staking: TestStakingContract;
|
||||
let weth: TestWethContract;
|
||||
|
||||
before(async () => {
|
||||
[payer] = await env.getAccountAddressesAsync();
|
||||
[payer, unauthorized] = await env.getAccountAddressesAsync();
|
||||
protocolFees = await TestProtocolFeesContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestProtocolFees,
|
||||
env.provider,
|
||||
@ -35,41 +37,128 @@ blockchainTests.resets('ProtocolFees', env => {
|
||||
await weth.approve(protocolFees.address, constants.ONE_ETHER).awaitTransactionSuccessAsync({ from: payer });
|
||||
});
|
||||
|
||||
async function collectAsync(
|
||||
poolId: string,
|
||||
amount: BigNumber,
|
||||
etherValue: BigNumber,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return protocolFees
|
||||
.collectProtocolFee(poolId, amount, weth.address)
|
||||
.awaitTransactionSuccessAsync({ from: payer, value: etherValue });
|
||||
}
|
||||
|
||||
async function transferFeesAsync(poolId: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return protocolFees.transferFeesForPool(poolId, staking.address, weth.address).awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
describe('FeeCollector', () => {
|
||||
it('should disallow unauthorized initialization', async () => {
|
||||
const pool = hexUtils.random();
|
||||
|
||||
await collectAsync(pool, constants.ONE_ETHER, constants.ZERO_AMOUNT);
|
||||
await transferFeesAsync(pool);
|
||||
|
||||
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()', () => {
|
||||
it('can collect a protocol fee multiple times', async () => {
|
||||
const poolId = hexUtils.random();
|
||||
const amount1 = new BigNumber(123456);
|
||||
const amount2 = new BigNumber(456789);
|
||||
const pool1 = hexUtils.random();
|
||||
const pool2 = hexUtils.random();
|
||||
|
||||
// Transfer amount1 via WETH.
|
||||
await protocolFees
|
||||
.collectProtocolFee(poolId, amount1, weth.address)
|
||||
.awaitTransactionSuccessAsync({ from: payer });
|
||||
it('should revert if WETH transfer fails', async () => {
|
||||
const tooMuch = constants.ONE_ETHER.plus(1);
|
||||
const tx = collectAsync(pool1, constants.ONE_ETHER.plus(1), constants.ZERO_AMOUNT);
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.Spender.SpenderERC20TransferFromFailedError(
|
||||
weth.address,
|
||||
payer,
|
||||
undefined,
|
||||
tooMuch,
|
||||
undefined,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// Send to staking contract.
|
||||
await protocolFees
|
||||
.transferFeesForPool(poolId, staking.address, weth.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
it('should revert if insufficient ETH transferred', async () => {
|
||||
const tooLittle = constants.ONE_ETHER.minus(1);
|
||||
const tx = collectAsync(pool1, constants.ONE_ETHER, tooLittle);
|
||||
return expect(tx).to.revertWith('FixinProtocolFees/ETHER_TRANSFER_FALIED');
|
||||
});
|
||||
|
||||
// Transfer amount2 via ETH.
|
||||
await protocolFees
|
||||
.collectProtocolFee(poolId, amount2, weth.address)
|
||||
.awaitTransactionSuccessAsync({ from: payer, value: amount2 });
|
||||
it('should accept WETH fee', async () => {
|
||||
const beforeWETH = await weth.balanceOf(payer).callAsync();
|
||||
await collectAsync(pool1, constants.ONE_ETHER, constants.ZERO_AMOUNT);
|
||||
const afterWETH = await weth.balanceOf(payer).callAsync();
|
||||
|
||||
// Send to staking contract again.
|
||||
await protocolFees
|
||||
.transferFeesForPool(poolId, staking.address, weth.address)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(beforeWETH.minus(afterWETH)).to.bignumber.eq(constants.ONE_ETHER);
|
||||
});
|
||||
|
||||
const balance = await staking.balanceForPool(poolId).callAsync();
|
||||
const wethBalance = await weth.balanceOf(staking.address).callAsync();
|
||||
it('should accept ETH fee', async () => {
|
||||
const beforeWETH = await weth.balanceOf(payer).callAsync();
|
||||
const beforeETH = await env.web3Wrapper.getBalanceInWeiAsync(payer);
|
||||
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
|
||||
const afterWETH = await weth.balanceOf(payer).callAsync();
|
||||
const afterETH = await env.web3Wrapper.getBalanceInWeiAsync(payer);
|
||||
|
||||
// Check that staking accounted for the collected ether properly.
|
||||
expect(balance).to.bignumber.eq(wethBalance);
|
||||
// We check for greater than 1 ether spent to allow for spending on gas.
|
||||
await expect(beforeETH.minus(afterETH)).to.bignumber.gt(constants.ONE_ETHER);
|
||||
return expect(beforeWETH).to.bignumber.eq(afterWETH);
|
||||
});
|
||||
|
||||
// We leave 1 wei behind, of both ETH and WETH, for gas reasons.
|
||||
const total = amount1.plus(amount2).minus(2);
|
||||
return expect(balance).to.bignumber.eq(total);
|
||||
it('should transfer both ETH and WETH', async () => {
|
||||
await collectAsync(pool1, constants.ONE_ETHER, constants.ZERO_AMOUNT);
|
||||
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
|
||||
await transferFeesAsync(pool1);
|
||||
|
||||
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
|
||||
|
||||
// We leave 1 wei behind of both ETH and WETH.
|
||||
return expect(balanceWETH).to.bignumber.eq(constants.ONE_ETHER.times(2).minus(2));
|
||||
});
|
||||
|
||||
it('should accept ETH after first transfer', async () => {
|
||||
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
|
||||
await transferFeesAsync(pool1);
|
||||
await collectAsync(pool1, constants.ONE_ETHER, constants.ONE_ETHER);
|
||||
await transferFeesAsync(pool1);
|
||||
|
||||
const balanceWETH = await weth.balanceOf(staking.address).callAsync();
|
||||
|
||||
// We leave 1 wei behind of both ETH and WETH
|
||||
return expect(balanceWETH).to.bignumber.eq(constants.ONE_ETHER.times(2).minus(2));
|
||||
});
|
||||
|
||||
it('should attribute fees correctly', async () => {
|
||||
const pool1Amount = new BigNumber(12345);
|
||||
const pool2Amount = new BigNumber(45678);
|
||||
|
||||
await collectAsync(pool1, pool1Amount, pool1Amount); // ETH
|
||||
await transferFeesAsync(pool1);
|
||||
await collectAsync(pool2, pool2Amount, constants.ZERO_AMOUNT); // WETH
|
||||
await transferFeesAsync(pool2);
|
||||
|
||||
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(pool1Balance.plus(pool2Balance));
|
||||
|
||||
// We leave 1 wei behind of both ETH and WETH.
|
||||
await expect(pool1Balance).to.bignumber.equal(pool1Amount.minus(2));
|
||||
|
||||
// Here we paid in WETH, so there's just 1 wei of WETH held back.
|
||||
return expect(pool2Balance).to.bignumber.equal(pool2Amount.minus(1));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user