Skip to content

Commit

Permalink
Merge pull request #136 from 1inch/feature/priority-fee-limiter
Browse files Browse the repository at this point in the history
add priority fee limiter
  • Loading branch information
ZumZoom authored Nov 2, 2023
2 parents c9429f3 + 7b5fa16 commit ff7909c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 1 deletion.
24 changes: 24 additions & 0 deletions contracts/SettlementExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ contract SettlementExtension is IPostInteraction, IAmountGetter, FeeBankCharger

error OnlyLimitOrderProtocol();
error ResolverIsNotWhitelisted();
error InvalidPriorityFee();

uint256 private constant _TAKING_FEE_BASE = 1e9;
uint256 private constant _ORDER_FEE_BASE_POINTS = 1e15;
Expand Down Expand Up @@ -119,7 +120,10 @@ contract SettlementExtension is IPostInteraction, IAmountGetter, FeeBankCharger
bytes calldata extraData
) external onlyLimitOrderProtocol {
(uint256 resolverFee, address integrator, uint256 integrationFee, bytes calldata whitelist) = _parseFeeData(extraData, order.makingAmount, makingAmount, takingAmount);

if (!_isWhitelisted(whitelist, taker)) revert ResolverIsNotWhitelisted();
if (!_isPriorityFeeValid()) revert InvalidPriorityFee();

_chargeFee(taker, resolverFee);
if (integrationFee > 0) {
IERC20(order.takerAsset.get()).safeTransferFrom(taker, integrator, integrationFee);
Expand Down Expand Up @@ -180,4 +184,24 @@ contract SettlementExtension is IPostInteraction, IAmountGetter, FeeBankCharger
return false;
}
}

/// @notice Validates priority fee according to the spec
/// https://snapshot.org/#/1inch.eth/proposal/0xa040c60050147a0f67042ae024673e92e813b5d2c0f748abf70ddfa1ed107cbe
/// For blocks with baseFee <10.6 gwei – the priorityFee is capped at 70% of the baseFee.
/// For blocks with baseFee between 10.6 gwei and 104.1 gwei – the priorityFee is capped at 50% of the baseFee.
/// For blocks with baseFee >104.1 gwei – priorityFee is capped at 65% of the block’s baseFee.
function _isPriorityFeeValid() private view returns(bool) {
unchecked {
uint256 baseFee = block.basefee;
uint256 priorityFee = tx.gasprice - baseFee;

if (baseFee < 10.6 gwei) {
return priorityFee * 100 <= baseFee * 70;
} else if (baseFee < 104.1 gwei) {
return priorityFee * 2 <= baseFee;
} else {
return priorityFee * 100 <= baseFee * 65;
}
}
}
}
7 changes: 6 additions & 1 deletion hardhat.networks.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
const networks = {};
const networks = {
hardhat: {
initialBaseFeePerGas: 1,
gasPrice: 1,
},
};
const etherscan = { apiKey: {}, customChains: [] };

if (process.env.ZKSYNC_PRIVATE_KEY) {
Expand Down
98 changes: 98 additions & 0 deletions test/PriorityFeeLimiter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const { expect, deployContract, time, ether, trim0x, constants } = require('@1inch/solidity-utils');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { buildOrder, buildMakerTraits } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');
const { initContractsForSettlement } = require('./helpers/fixtures');
const hre = require('hardhat');
const { ethers, network } = hre;

describe('PriorityFeeLimiter', function () {
before(async function () {
if (hre.__SOLIDITY_COVERAGE_RUNNING) { this.skip(); }
});

after(async function () {
await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0x1']);
});

async function prepare() {
const { contracts: { dai, weth }, accounts: { owner } } = await initContractsForSettlement();
const settlementExtension = await deployContract('SettlementExtension', [owner.address, weth.address]);
const currentTime = (await time.latest()) - time.duration.minutes(1);

const postInteractionData = ethers.utils.solidityPack(
['uint8', 'uint32', 'bytes10', 'uint16'],
[0, currentTime, '0x' + owner.address.substring(22), 0],
);

const order = buildOrder({
maker: owner.address,
makerAsset: dai.address,
takerAsset: weth.address,
makingAmount: ether('10'),
takingAmount: ether('1'),
makerTraits: buildMakerTraits(),
}, {
postInteraction: settlementExtension.address + trim0x(postInteractionData),
});

return { order, owner, postInteractionData, settlementExtension };
}

function sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, maxPriorityFeePerGas) {
return settlementExtension.postInteraction(
order, '0x', constants.ZERO_BYTES32, owner.address, ether('10'), ether('1'), ether('10'), postInteractionData,
{ maxPriorityFeePerGas },
);
}

it('8 gwei base, 4 gwei priority should work', async function () {
const { order, owner, postInteractionData, settlementExtension } = await loadFixture(prepare);

await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0x1dcd65000']); // 8 gwei

await sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, 4000000000);
});

it('8 gwei base, 6 gwei priority should not work', async function () {
const { order, owner, postInteractionData, settlementExtension } = await loadFixture(prepare);

await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0x1dcd65000']); // 8 gwei

const postInteractionTxn = sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, 6000000000);
await expect(postInteractionTxn).to.be.revertedWithCustomError(settlementExtension, 'InvalidPriorityFee');
});

it('50 gwei base, 25 gwei priority should work', async function () {
const { order, owner, postInteractionData, settlementExtension } = await loadFixture(prepare);

await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0xba43b7400']); // 50 gwei

await sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, 25000000000);
});

it('50 gwei base, 26 gwei priority should not work', async function () {
const { order, owner, postInteractionData, settlementExtension } = await loadFixture(prepare);

await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0xba43b7400']); // 50 gwei

const postInteractionTxn = sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, 26000000000);
await expect(postInteractionTxn).to.be.revertedWithCustomError(settlementExtension, 'InvalidPriorityFee');
});

it('150 gwei base, 90 gwei priority should work', async function () {
const { order, owner, postInteractionData, settlementExtension } = await loadFixture(prepare);

await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0x22ecb25c00']); // 150 gwei

await sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, 90000000000);
});

it('150 gwei base, 100 gwei priority should not work', async function () {
const { order, owner, postInteractionData, settlementExtension } = await loadFixture(prepare);

await network.provider.send('hardhat_setNextBlockBaseFeePerGas', ['0x22ecb25c00']); // 150 gwei

const postInteractionTxn = sendPostInteractionTxn(settlementExtension, order, owner, postInteractionData, 100000000000);
await expect(postInteractionTxn).to.be.revertedWithCustomError(settlementExtension, 'InvalidPriorityFee');
});
});

0 comments on commit ff7909c

Please sign in to comment.