Skip to content

Commit

Permalink
Merge pull request #277 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 Oct 9, 2023
2 parents da3e187 + d05444b commit 086c651
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
26 changes: 26 additions & 0 deletions contracts/helpers/PrioirityFeeLimiter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

/// @title A helper contract for executing boolean functions on arbitrary target call results
contract PriorityFeeLimiter {
/// @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() public 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;
}
}
}
}
12 changes: 12 additions & 0 deletions deploy/deploy-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ module.exports = async ({ getNamedAccounts, deployments }) => {
address: callsSimulator.address,
});
}

const priorityFeeLimiter = await deploy('PriorityFeeLimiter', {
from: deployer,
});

console.log('PriorityFeeLimiter deployed to:', priorityFeeLimiter.address);

if (await getChainId() !== '31337') {
await hre.run('verify:verify', {
address: priorityFeeLimiter.address,
});
}
};

module.exports.skip = async () => true;
59 changes: 59 additions & 0 deletions deployments/mainnet/PriorityFeeLimiter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"address": "0x5E92d4021e49f9A2967b4EA1d20213B3A1c7c912",
"abi": [
{
"inputs": [],
"name": "isPriorityFeeValid",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"transactionHash": "0x1d1ffe931a812a2af71af25b841f63ed6e2a24ee2cdf79eed1e4a2bd64d95c2c",
"receipt": {
"to": null,
"from": "0x11799622F4D98A24514011E8527B969f7488eF47",
"contractAddress": "0x5E92d4021e49f9A2967b4EA1d20213B3A1c7c912",
"transactionIndex": 117,
"gasUsed": "101367",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0x263d3939a79ce71ca11bc2429e003caa0d454342999049de735ae0af77f132c3",
"transactionHash": "0x1d1ffe931a812a2af71af25b841f63ed6e2a24ee2cdf79eed1e4a2bd64d95c2c",
"logs": [],
"blockNumber": 18311797,
"cumulativeGasUsed": "11544912",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
"solcInputHash": "6e7c6f92a69228f0d66327ee7f30987a",
"metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"isPriorityFeeValid\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"A helper contract for executing boolean functions on arbitrary target call results\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"isPriorityFeeValid()\":{\"notice\":\"Validates priority fee according to the spec https://snapshot.org/#/1inch.eth/proposal/0xa040c60050147a0f67042ae024673e92e813b5d2c0f748abf70ddfa1ed107cbe For blocks with baseFee <10.6 gwei \\u2013 the priorityFee is capped at 70% of the baseFee. For blocks with baseFee between 10.6 gwei and 104.1 gwei \\u2013 the priorityFee is capped at 50% of the baseFee. For blocks with baseFee >104.1 gwei \\u2013 priorityFee is capped at 65% of the block\\u2019s baseFee.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/helpers/PrioirityFeeLimiter.sol\":\"PriorityFeeLimiter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"contracts/helpers/PrioirityFeeLimiter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.19;\\n\\n/// @title A helper contract for executing boolean functions on arbitrary target call results\\ncontract PriorityFeeLimiter {\\n /// @notice Validates priority fee according to the spec\\n /// https://snapshot.org/#/1inch.eth/proposal/0xa040c60050147a0f67042ae024673e92e813b5d2c0f748abf70ddfa1ed107cbe\\n /// For blocks with baseFee <10.6 gwei \\u2013 the priorityFee is capped at 70% of the baseFee.\\n /// For blocks with baseFee between 10.6 gwei and 104.1 gwei \\u2013 the priorityFee is capped at 50% of the baseFee.\\n /// For blocks with baseFee >104.1 gwei \\u2013 priorityFee is capped at 65% of the block\\u2019s baseFee.\\n function isPriorityFeeValid() public view returns(bool) {\\n unchecked {\\n uint256 baseFee = block.basefee;\\n uint256 priorityFee = tx.gasprice - baseFee;\\n\\n if (baseFee < 10.6 gwei) {\\n return priorityFee * 100 <= baseFee * 70;\\n } else if (baseFee < 104.1 gwei) {\\n return priorityFee * 2 <= baseFee;\\n } else {\\n return priorityFee * 100 <= baseFee * 65;\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xec368259e09381c211267f2e735a08a7229efe350c6040bd12553caa40ed3dec\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608080604052346100155760de908161001b8239f35b600080fdfe6080806040526004361015601257600080fd5b600090813560e01c630202470814602857600080fd5b34606357817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112606357602090605d6067565b15158152f35b5080fd5b483a03640277cf2a0048106000146085576064604648029102111590565b64183cd7f100481015609b57489060011b111590565b606460414802910211159056fea2646970667358221220fe767365ecbf40522ecd1de1cb05111223125fde69ba80a98aa04be6f0c80f4b64736f6c63430008130033",
"deployedBytecode": "0x6080806040526004361015601257600080fd5b600090813560e01c630202470814602857600080fd5b34606357817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112606357602090605d6067565b15158152f35b5080fd5b483a03640277cf2a0048106000146085576064604648029102111590565b64183cd7f100481015609b57489060011b111590565b606460414802910211159056fea2646970667358221220fe767365ecbf40522ecd1de1cb05111223125fde69ba80a98aa04be6f0c80f4b64736f6c63430008130033",
"devdoc": {
"kind": "dev",
"methods": {},
"title": "A helper contract for executing boolean functions on arbitrary target call results",
"version": 1
},
"userdoc": {
"kind": "user",
"methods": {
"isPriorityFeeValid()": {
"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."
}
},
"version": 1
},
"storageLayout": {
"storage": [],
"types": null
}
}
106 changes: 106 additions & 0 deletions test/PriorityFeeLimiter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
const { expect } = require('@1inch/solidity-utils');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { ether } = require('./helpers/utils');
const { signOrder, buildOrder, buildTakerTraits } = require('./helpers/orderUtils');
const { deploySwapTokens } = require('./helpers/fixtures');
const hre = require('hardhat');
const { ethers, network } = hre;

describe('PriorityFeeLimiter', function () {
let addr, addr1;

before(async function () {
if (hre.__SOLIDITY_COVERAGE_RUNNING) { this.skip(); }
[addr, addr1] = await ethers.getSigners();
});

async function deployContractsAndInit () {
const { dai, weth, swap, chainId } = await deploySwapTokens();

await dai.mint(addr.address, ether('2000'));
await weth.connect(addr1).deposit({ value: ether('1') });

await dai.approve(swap.address, ether('2000'));
await weth.connect(addr1).approve(swap.address, ether('1'));

const PriorityFeeLimiter = await ethers.getContractFactory('PriorityFeeLimiter');
const priorityFeeLimiter = await PriorityFeeLimiter.deploy();
await priorityFeeLimiter.deployed();

const order = buildOrder(
{
makerAsset: weth.address,
takerAsset: dai.address,
makingAmount: ether('1'),
takingAmount: ether('2000'),
maker: addr1.address,
},
{
predicate: swap.interface.encodeFunctionData('arbitraryStaticCall', [
priorityFeeLimiter.address,
priorityFeeLimiter.interface.encodeFunctionData('isPriorityFeeValid'),
]),
},
);
const signature = await signOrder(order, chainId, swap.address, addr1);
const { r, _vs: vs } = ethers.utils.splitSignature(signature);
const takerTraits = buildTakerTraits({
makingAmount: true,
extension: order.extension,
minReturn: order.takingAmount,
});

return { dai, weth, swap, order, r, vs, takerTraits };
};

it('8 gwei base, 4 gwei priority should work', async function () {
const { swap, order, r, vs, takerTraits } = await loadFixture(deployContractsAndInit);

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

Check failure on line 59 in test/PriorityFeeLimiter.js

View workflow job for this annotation

GitHub Actions / lint

Multiple spaces found before '// 8 gwei'

await swap.fillOrderArgs(order, r, vs, order.makingAmount, takerTraits.traits, takerTraits.args, { maxPriorityFeePerGas: 4000000000 });
});

it('8 gwei base, 6 gwei priority should not work', async function () {
const { swap, order, r, vs, takerTraits } = await loadFixture(deployContractsAndInit);

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

Check failure on line 67 in test/PriorityFeeLimiter.js

View workflow job for this annotation

GitHub Actions / lint

Multiple spaces found before '// 8 gwei'

const fillTx = swap.fillOrderArgs(order, r, vs, order.makingAmount, takerTraits.traits, takerTraits.args, { maxPriorityFeePerGas: 6000000000 });
await expect(fillTx).to.revertedWithCustomError(swap, 'PredicateIsNotTrue');
});

it('50 gwei base, 25 gwei priority should work', async function () {
const { swap, order, r, vs, takerTraits } = await loadFixture(deployContractsAndInit);

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

Check failure on line 76 in test/PriorityFeeLimiter.js

View workflow job for this annotation

GitHub Actions / lint

Multiple spaces found before '// 50 gwei'

await swap.fillOrderArgs(order, r, vs, order.makingAmount, takerTraits.traits, takerTraits.args, { maxPriorityFeePerGas: 25000000000 });
});

it('50 gwei base, 26 gwei priority should not work', async function () {
const { swap, order, r, vs, takerTraits } = await loadFixture(deployContractsAndInit);

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

Check failure on line 84 in test/PriorityFeeLimiter.js

View workflow job for this annotation

GitHub Actions / lint

Multiple spaces found before '// 50 gwei'

const fillTx = swap.fillOrderArgs(order, r, vs, order.makingAmount, takerTraits.traits, takerTraits.args, { maxPriorityFeePerGas: 26000000000 });
await expect(fillTx).to.revertedWithCustomError(swap, 'PredicateIsNotTrue');
});

it('150 gwei base, 90 gwei priority should work', async function () {
const { swap, order, r, vs, takerTraits } = await loadFixture(deployContractsAndInit);

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

Check failure on line 93 in test/PriorityFeeLimiter.js

View workflow job for this annotation

GitHub Actions / lint

Multiple spaces found before '// 150 gwei'

await swap.fillOrderArgs(order, r, vs, order.makingAmount, takerTraits.traits, takerTraits.args, { maxPriorityFeePerGas: 90000000000 });
});

it('150 gwei base, 100 gwei priority should not work', async function () {
const { swap, order, r, vs, takerTraits } = await loadFixture(deployContractsAndInit);

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

Check failure on line 101 in test/PriorityFeeLimiter.js

View workflow job for this annotation

GitHub Actions / lint

Multiple spaces found before '// 150 gwei'

const fillTx = swap.fillOrderArgs(order, r, vs, order.makingAmount, takerTraits.traits, takerTraits.args, { maxPriorityFeePerGas: 100000000000 });
await expect(fillTx).to.revertedWithCustomError(swap, 'PredicateIsNotTrue');
});
});

0 comments on commit 086c651

Please sign in to comment.