Skip to content

Commit

Permalink
Patch all another FeeTaker tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zZoMROT committed Jul 21, 2024
1 parent 3f1b081 commit d4de525
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 147 deletions.
38 changes: 33 additions & 5 deletions contracts/extensions/FeeTaker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IOrderMixin } from "../interfaces/IOrderMixin.sol";
import { IPostInteraction } from "../interfaces/IPostInteraction.sol";
import { MakerTraits, MakerTraitsLib } from "../libraries/MakerTraitsLib.sol";
import { FeeTakerLib } from "../libraries/FeeTakerLib.sol";
import { FeeBank } from "./FeeBank.sol";
import { FeeBankCharger } from "./FeeBankCharger.sol";

Expand All @@ -22,7 +21,6 @@ contract FeeTaker is IPostInteraction, FeeBankCharger, Ownable {
using SafeERC20 for IERC20;
using UniERC20 for IERC20;
using MakerTraitsLib for MakerTraits;
using FeeTakerLib for bytes;

/**
* @dev The caller is not the limit order protocol contract.
Expand All @@ -36,6 +34,9 @@ contract FeeTaker is IPostInteraction, FeeBankCharger, Ownable {

/// @dev Allows fees in range [1e-5, 0.65535]
uint256 internal constant _FEE_BASE = 1e5;
uint256 internal constant _WHITELIST_SHIFT = 3;
bytes1 internal constant _RESOLVER_FEE_FLAG = 0x01;
bytes1 internal constant _INTEGRATOR_FEE_FLAG = 0x02;

address private immutable _LIMIT_ORDER_PROTOCOL;
address private immutable _WETH;
Expand Down Expand Up @@ -85,6 +86,33 @@ contract FeeTaker is IPostInteraction, FeeBankCharger, Ownable {
}
}

/**
* @notice Checks if the resolver fee is enabled
* @param bitmap Bitmap indicating various usage flags and values
* @return True if the resolver fee is enabled
*/
function _resolverFeeEnabled(bytes1 bitmap) internal pure returns (bool) {
return bitmap & _RESOLVER_FEE_FLAG == _RESOLVER_FEE_FLAG;
}

/**
* @notice Checks if the integrator fee is enabled
* @param bitmap Bitmap indicating various usage flags and values
* @return True if the integrator fee is enabled
*/
function _integratorFeeEnabled(bytes1 bitmap) internal pure returns (bool) {
return bitmap & _INTEGRATOR_FEE_FLAG == _INTEGRATOR_FEE_FLAG;
}

/**
* @notice Gets the number of resolvers in the whitelist
* @param bitmap Bitmap indicating various usage flags and values
* @return The number of resolvers in the whitelist
*/
function _resolversCount(bytes1 bitmap) internal pure returns (uint256) {
return uint8(bitmap) >> _WHITELIST_SHIFT;
}

/**
* @notice See {IPostInteraction-postInteraction}.
* @dev Takes the fee in taking tokens and transfers the rest to the maker.
Expand Down Expand Up @@ -114,12 +142,12 @@ contract FeeTaker is IPostInteraction, FeeBankCharger, Ownable {
uint256 resolverFee;
{
uint256 resolverFeePercent;
if (extraData.resolverFeeEnabled()) {
if (_resolverFeeEnabled(extraData[extraData.length - 1])) {
resolverFeePercent = uint16(bytes2(extraData));
extraData = extraData[2:];
}
uint256 integratorFeePercent;
if (extraData.integratorFeeEnabled()) {
if (_integratorFeeEnabled(extraData[extraData.length - 1])) {
integratorFeePercent = uint16(bytes2(extraData));
extraData = extraData[2:];
}
Expand All @@ -128,7 +156,7 @@ contract FeeTaker is IPostInteraction, FeeBankCharger, Ownable {
resolverFee = Math.mulDiv(takingAmount, resolverFeePercent, denominator);
}

uint256 whitelistEnd = extraData.resolversCount() * 10;
uint256 whitelistEnd = _resolversCount(extraData[extraData.length - 1]) * 10;
uint256 maxFee = integratorFee + 2 * resolverFee;
uint256 fee = maxFee;
uint256 cashback;
Expand Down
50 changes: 0 additions & 50 deletions contracts/libraries/FeeTakerLib.sol

This file was deleted.

119 changes: 31 additions & 88 deletions test/FeeTaker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { expect } = require('@1inch/solidity-utils');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { deploySwapTokens } = require('./helpers/fixtures');
const { buildOrder, buildTakerTraits, signOrder, buildMakerTraits, buildFeeTakerPostInteractionData } = require('./helpers/orderUtils');
const { ether, trim0x } = require('./helpers/utils');
const { ether } = require('./helpers/utils');

describe('FeeTaker', function () {
let addr, addr1, addr2, addr3;
Expand Down Expand Up @@ -34,7 +34,7 @@ describe('FeeTaker', function () {
const feeBank = await ethers.getContractAt('FeeBank', await feeTaker.FEE_BANK());

await weth.approve(feeBank, ether('1'));
await feeBank.deposit(ether('1'))
await feeBank.deposit(ether('1'));

return { dai, weth, inch, swap, chainId, feeTaker, feeBank };
};
Expand All @@ -44,8 +44,6 @@ describe('FeeTaker', function () {

const makingAmount = ether('300');
const takingAmount = ether('0.3');
const fee = 0;
const feeRecipient = addr2.address;

const order = buildOrder(
{
Expand All @@ -57,7 +55,12 @@ describe('FeeTaker', function () {
takingAmount,
},
{
postInteraction: await feeTaker.getAddress() + trim0x(ethers.solidityPacked(['uint16', 'address'], [fee, feeRecipient])),
postInteraction: buildFeeTakerPostInteractionData({
feeTaker: await feeTaker.getAddress(),
integratorFee: 0n,
resolverFee: 0n,
whitelist: [addr.address],
}),
},
);

Expand All @@ -66,6 +69,7 @@ describe('FeeTaker', function () {
extension: order.extension,
});
const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args);
console.log(`GasUsed: ${(await (await fillTx).wait()).gasUsed.toString()}`);
await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]);
await expect(fillTx).to.changeTokenBalances(weth, [addr, addr1, addr2], [-takingAmount, takingAmount, 0]);
});
Expand All @@ -75,9 +79,6 @@ describe('FeeTaker', function () {

const makingAmount = ether('300');
const takingAmount = ether('0.3');
const fee = 0;
const feeRecipient = addr2.address;
const makerReceiver = addr3.address;

const order = buildOrder(
{
Expand All @@ -89,8 +90,13 @@ describe('FeeTaker', function () {
takingAmount,
},
{
postInteraction: await feeTaker.getAddress() +
trim0x(ethers.solidityPacked(['uint16', 'address', 'address'], [fee, feeRecipient, makerReceiver])),
postInteraction: buildFeeTakerPostInteractionData({
feeTaker: await feeTaker.getAddress(),
integratorFee: 0n,
resolverFee: 0n,
makerReceiver: addr3.address,
whitelist: [addr.address],
}),
},
);

Expand All @@ -99,11 +105,12 @@ describe('FeeTaker', function () {
extension: order.extension,
});
const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args);
console.log(`GasUsed: ${(await (await fillTx).wait()).gasUsed.toString()}`);
await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]);
await expect(fillTx).to.changeTokenBalances(weth, [addr, addr1, addr2, addr3], [-takingAmount, 0, 0, takingAmount]);
});

it.only('should charge fee NOT by FEE_BANK when in whitelist', async function () {
it('should charge fee NOT by FEE_BANK when in whitelist', async function () {
const { dai, weth, swap, chainId, feeTaker } = await loadFixture(deployContractsAndInit);

const makingAmount = ether('300');
Expand Down Expand Up @@ -148,7 +155,7 @@ describe('FeeTaker', function () {
);
});

it.only('should charge fee by FEE_BANK when in whitelist', async function () {
it('should charge fee by FEE_BANK when in whitelist', async function () {
const { dai, weth, swap, chainId, feeTaker, feeBank } = await loadFixture(deployContractsAndInit);

await feeBank.setPayWithFeeBank(true);
Expand Down Expand Up @@ -196,7 +203,7 @@ describe('FeeTaker', function () {
expect(await feeBank.availableCredit(addr)).to.be.equal(ether('1') - feeCalculated);
});

it.only('should charge fee NOT by FEE_BANK when out of whitelist', async function () {
it('should charge fee NOT by FEE_BANK when out of whitelist', async function () {
const { dai, weth, swap, chainId, feeTaker } = await loadFixture(deployContractsAndInit);

const makingAmount = ether('300');
Expand Down Expand Up @@ -240,7 +247,7 @@ describe('FeeTaker', function () {
);
});

it.only('should charge fee by FEE_BANK when out of whitelist', async function () {
it('should charge fee by FEE_BANK when out of whitelist', async function () {
const { dai, weth, swap, chainId, feeTaker, feeBank } = await loadFixture(deployContractsAndInit);

await feeBank.setPayWithFeeBank(true);
Expand Down Expand Up @@ -286,48 +293,12 @@ describe('FeeTaker', function () {
expect(await feeBank.availableCredit(addr)).to.be.equal(ether('1') - feeCalculated);
});

it('should charge fee and send the rest to the maker receiver', async function () {
const { dai, weth, swap, chainId, feeTaker } = await loadFixture(deployContractsAndInit);

const makingAmount = ether('300');
const takingAmount = ether('0.3');
const fee = BigInt(1e4);
const feeCalculated = takingAmount * fee / BigInt(1e5);
const feeRecipient = addr2.address;
const makerReceiver = addr3.address;

const order = buildOrder(
{
maker: addr1.address,
receiver: await feeTaker.getAddress(),
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount,
takingAmount,
},
{
postInteraction: await feeTaker.getAddress() +
trim0x(ethers.solidityPacked(['uint16', 'address', 'address'], [fee, feeRecipient, makerReceiver])),
},
);

const { r, yParityAndS: vs } = ethers.Signature.from(await signOrder(order, chainId, await swap.getAddress(), addr1));
const takerTraits = buildTakerTraits({
extension: order.extension,
});
const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args);
await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]);
await expect(fillTx).to.changeTokenBalances(weth, [addr, addr1, addr2, addr3], [-takingAmount, 0, feeCalculated, takingAmount - feeCalculated]);
});

it('should charge fee in eth', async function () {
const { dai, weth, swap, chainId, feeTaker } = await loadFixture(deployContractsAndInit);

const makingAmount = ether('300');
const takingAmount = ether('0.3');
const fee = BigInt(1e4);
const feeCalculated = takingAmount * fee / BigInt(1e5);
const feeRecipient = addr2.address;
const integratorFee = BigInt(1e4);

const order = buildOrder(
{
Expand All @@ -340,53 +311,25 @@ describe('FeeTaker', function () {
makerTraits: buildMakerTraits({ unwrapWeth: true }),
},
{
postInteraction: await feeTaker.getAddress() + trim0x(ethers.solidityPacked(['uint16', 'address'], [fee, feeRecipient])),
postInteraction: buildFeeTakerPostInteractionData({
feeTaker: await feeTaker.getAddress(),
integratorFee,
resolverFee: 0n,
feeRecipient: addr2.address,
whitelist: [addr.address],
}),
},
);

const { r, yParityAndS: vs } = ethers.Signature.from(await signOrder(order, chainId, await swap.getAddress(), addr1));
const takerTraits = buildTakerTraits({
extension: order.extension,
});
const feeCalculated = takingAmount * integratorFee / (BigInt(1e5) + integratorFee);
const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args);
console.log(`GasUsed: ${(await (await fillTx).wait()).gasUsed.toString()}`);
await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]);
await expect(fillTx).to.changeTokenBalance(weth, addr, -takingAmount);
await expect(fillTx).to.changeEtherBalances([addr1, addr2], [takingAmount - feeCalculated, feeCalculated]);
});

it('should charge fee in eth and send the rest to the maker receiver', async function () {
const { dai, weth, swap, chainId, feeTaker } = await loadFixture(deployContractsAndInit);

const makingAmount = ether('300');
const takingAmount = ether('0.3');
const fee = BigInt(1e4);
const feeCalculated = takingAmount * fee / BigInt(1e5);
const feeRecipient = addr2.address;
const makerReceiver = addr3.address;

const order = buildOrder(
{
maker: addr1.address,
receiver: await feeTaker.getAddress(),
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits({ unwrapWeth: true }),
},
{
postInteraction: await feeTaker.getAddress() +
trim0x(ethers.solidityPacked(['uint16', 'address', 'address'], [fee, feeRecipient, makerReceiver])),
},
);

const { r, yParityAndS: vs } = ethers.Signature.from(await signOrder(order, chainId, await swap.getAddress(), addr1));
const takerTraits = buildTakerTraits({
extension: order.extension,
});
const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args);
await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]);
await expect(fillTx).to.changeTokenBalance(weth, addr, -takingAmount);
await expect(fillTx).to.changeEtherBalances([addr1, addr2, addr3], [0, feeCalculated, takingAmount - feeCalculated]);
});
});
8 changes: 4 additions & 4 deletions test/helpers/orderUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ function skipMakerPermit (amount) {
return BigInt(amount) | BigInt(buildTakerTraits({ skipMakerPermit: true }).traits);
}

function buildExtensionsBitmapData({
function buildExtensionsBitmapData ({
whitelistSize = 1,
feeType = 0,
} = {}) {
Expand All @@ -290,8 +290,8 @@ function buildFeeTakerPostInteractionData ({
integratorFee = 0n,
resolverFee = 0n,
feeRecipient,
makerReceiver,
whitelist = [],
receiver,
}) {
// * 2 bytes — Resolver fee percentage (in 1e5). Should be skipped if resolver fee usage flag is not setted.
// * 2 bytes — Integrator fee percentage (in 1e5). Should be skipped if integration fee usage flag is not setted.
Expand All @@ -311,8 +311,8 @@ function buildFeeTakerPostInteractionData ({
if (feeRecipient) {
data += trim0x(feeRecipient);
}
if (receiver) {
data += trim0x(receiver);
if (makerReceiver) {
data += trim0x(makerReceiver);
}

const feeType = (BigInt(resolverFee) > 0n ? 1 : 0) + (BigInt(integratorFee) > 0n ? 2 : 0);
Expand Down

0 comments on commit d4de525

Please sign in to comment.