Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SC-1369] Feature/leftovers #183

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions contracts/SimpleSettlement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ contract SimpleSettlement is FeeTaker {
uint256 private constant _GAS_PRICE_BASE = 1_000_000; // 1000 means 1 Gwei

error AllowedTimeViolation();
error InvalidProtocolSurplusFee();
error InvalidEstimatedTakingAmount();

/**
* @notice Initializes the contract.
Expand Down Expand Up @@ -177,4 +179,35 @@ contract SimpleSettlement is FeeTaker {
}
}
}

/**
* @dev Calculates fee amounts depending on whether the taker is in the whitelist and whether they have an _ACCESS_TOKEN.
* @param order The user's order.
* @param taker The taker address.
* @param takingAmount The amount of the asset being taken.
* @param extraData The extra data has the following format:
* ```
* 2 bytes — integrator fee percentage (in 1e5)
* 1 bytes - integrator rev share percentage (in 1e2)
* 2 bytes — resolver fee percentage (in 1e5)
* 32 bytes - estimated taking amount
* 1 byte - protocol surplus fee (in 1e2)
* ```
*/
function _getFeeAmounts(IOrderMixin.Order calldata order, address taker, uint256 takingAmount, uint256 makingAmount, bytes calldata extraData) internal override virtual returns (uint256 integratorFeeAmount, uint256 protocolFeeAmount, bytes calldata tail) {
(integratorFeeAmount, protocolFeeAmount, tail) = super._getFeeAmounts(order, taker, takingAmount, makingAmount, extraData);

uint256 estimatedTakingAmount = uint256(bytes32(tail));
if (Math.mulDiv(estimatedTakingAmount, order.makingAmount, makingAmount) < order.takingAmount) {
revert InvalidEstimatedTakingAmount();
}

uint256 actualTakingAmount = takingAmount - integratorFeeAmount - protocolFeeAmount;
if (actualTakingAmount > estimatedTakingAmount) {
uint256 protocolSurplusFee = uint256(uint8(bytes1(tail[32:])));
if (protocolSurplusFee > _BASE_1E2) revert InvalidProtocolSurplusFee();
protocolFeeAmount += Math.mulDiv(actualTakingAmount - estimatedTakingAmount, protocolSurplusFee, _BASE_1E2);
}
tail = tail[33:];
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"dependencies": {
"@1inch/delegating": "1.1.0",
"@1inch/limit-order-protocol-contract": "4.2.2",
"@1inch/limit-order-protocol-contract": "github:1inch/limit-order-protocol#feature/prepare_for_reusing_feeTaker",
"@1inch/solidity-utils": "6.2.0",
"@1inch/st1inch": "2.2.0",
"@openzeppelin/contracts": "5.1.0"
Expand Down
13 changes: 8 additions & 5 deletions test/GasBump.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const { time, ether, constants } = require('@1inch/solidity-utils');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { buildOrder, buildMakerTraits, buildFeeTakerExtensions } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');
const { buildOrder, buildMakerTraits } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');
const { initContractsForSettlement } = require('./helpers/fixtures');
const { buildAuctionDetails } = require('./helpers/fusionUtils');
const { buildAuctionDetails, buildSettlementExtensions } = require('./helpers/fusionUtils');
const hre = require('hardhat');
const { network, ethers } = hre;

Expand All @@ -17,6 +17,8 @@ describe('GasBump', function () {

async function prepare() {
const { contracts: { dai, weth, accessToken }, accounts: { owner } } = await initContractsForSettlement();
const makingAmount = ether('10');
const takingAmount = ether('1');
const GasBumpChecker = await ethers.getContractFactory('GasBumpChecker');
const checker = await GasBumpChecker.deploy(accessToken, weth, owner);
const currentTime = (await time.latest()) - time.duration.minutes(1) + 1;
Expand All @@ -28,8 +30,9 @@ describe('GasBump', function () {
points: [[500000, 60]],
});

const extensions = buildFeeTakerExtensions({
const extensions = buildSettlementExtensions({
feeTaker: await checker.getAddress(),
estimatedTakingAmount: takingAmount,
getterExtraPrefix: auctionDetails,
});

Expand All @@ -38,8 +41,8 @@ describe('GasBump', function () {
maker: owner.address,
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount: ether('10'),
takingAmount: ether('1'),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits(),
},
);
Expand Down
105 changes: 86 additions & 19 deletions test/MeasureGas.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ const { ethers } = hre;
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { constants, time, expect, ether, trim0x, deployContract } = require('@1inch/solidity-utils');
const { deploySwapTokens, getChainId, initContractsForSettlement } = require('./helpers/fixtures');
const { buildAuctionDetails, buildCalldataForOrder } = require('./helpers/fusionUtils');
const { buildAuctionDetails, buildCalldataForOrder, buildSettlementExtensions } = require('./helpers/fusionUtils');
const { buildOrder: buildOrderV1, buildSalt: buildSaltV1, signOrder: signOrderV1 } = require('./helpers/orderUtilsV1');
const { buildOrder, signOrder, buildTakerTraits, buildMakerTraits, buildFeeTakerExtensions } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');
const { buildOrder, signOrder, buildTakerTraits, buildMakerTraits } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');

const RESOLVERS_NUMBER = 10;

Expand Down Expand Up @@ -222,10 +222,13 @@ describe('MeasureGas', function () {
describe('Extension check', function () {
it('post interaction', async function () {
const { contracts: { dai, weth, accessToken }, accounts: { owner } } = await loadFixture(initContractsAndApproves);
const makingAmount = ether('10');
const takingAmount = ether('1');
const settlementExtension = await deployContract('Settlement', [owner, weth, accessToken, weth, owner]);
const auction = await buildAuctionDetails();
const extensions = buildFeeTakerExtensions({
const extensions = buildSettlementExtensions({
feeTaker: await settlementExtension.getAddress(),
estimatedTakingAmount: takingAmount,
getterExtraPrefix: auction.details,
whitelistPostInteraction: '0x0000000000',
});
Expand All @@ -235,27 +238,29 @@ describe('MeasureGas', function () {
maker: owner.address,
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount: ether('10'),
takingAmount: ether('1'),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits(),
},
extensions,
);

await settlementExtension.postInteraction(order, '0x', constants.ZERO_BYTES32, owner.address, ether('10'), ether('1'), ether('10'), '0x' + extensions.postInteraction.substring(42));
await settlementExtension.postInteraction(order, '0x', constants.ZERO_BYTES32, owner.address, makingAmount, takingAmount, makingAmount, '0x' + extensions.postInteraction.substring(42));
});

it('making getter', async function () {
const { contracts: { dai, weth, settlementExtension }, accounts: { owner } } = await loadFixture(initContractsAndApproves);

const makingAmount = ether('10');
const takingAmount = ether('1');
const currentTime = await time.latest();
const { details } = await buildAuctionDetails({
startTime: currentTime - time.duration.minutes(5),
initialRateBump: 900000,
points: [[800000, 100], [700000, 100], [600000, 100], [500000, 100], [400000, 100]],
});
const extensions = buildFeeTakerExtensions({
const extensions = buildSettlementExtensions({
feeTaker: await settlementExtension.getAddress(),
estimatedTakingAmount: takingAmount,
getterExtraPrefix: details,
whitelistPostInteraction: '0x0000000000',
});
Expand All @@ -265,14 +270,14 @@ describe('MeasureGas', function () {
maker: owner.address,
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount: ether('10'),
takingAmount: ether('1'),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits(),
},
extensions,
);

await settlementExtension.getMakingAmount(order, '0x', constants.ZERO_BYTES32, constants.ZERO_ADDRESS, ether('1'), ether('10'), '0x' + extensions.makingAmountData.substring(42));
await settlementExtension.getMakingAmount(order, '0x', constants.ZERO_BYTES32, constants.ZERO_ADDRESS, takingAmount, makingAmount, '0x' + extensions.makingAmountData.substring(42));
});
});

Expand All @@ -283,21 +288,24 @@ describe('MeasureGas', function () {
accounts: { alice, owner },
others: { chainId },
} = await loadFixture(initContractsForSettlement);
const makingAmount = ether('100');
const takingAmount = ether('0.1');
const auction = await buildAuctionDetails();

const orderData = {
maker: alice.address,
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount: ether('100'),
takingAmount: ether('0.1'),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits(),
};

const order = buildOrder(
orderData,
buildFeeTakerExtensions({
buildSettlementExtensions({
feeTaker: await settlement.getAddress(),
estimatedTakingAmount: takingAmount,
getterExtraPrefix: auction.details,
whitelistPostInteraction: '0x0000000000',
}),
Expand All @@ -307,25 +315,25 @@ describe('MeasureGas', function () {

const takerTraits = buildTakerTraits({
makingAmount: true,
threshold: ether('0.1'),
threshold: takingAmount,
extension: order.extension,
});

await weth.approve(lopv4, ether('0.1'));
await weth.approve(lopv4, takingAmount);

const tx = await lopv4.fillOrderArgs(
order,
r,
vs,
ether('100'),
makingAmount,
takerTraits.traits,
takerTraits.args,
);

console.log(`1 fill for 1 order gasUsed: ${(await tx.wait()).gasUsed}`);

await expect(tx).to.changeTokenBalances(dai, [owner, alice], [ether('100'), ether('-100')]);
await expect(tx).to.changeTokenBalances(weth, [owner, alice], [ether('-0.1'), ether('0.1')]);
await expect(tx).to.changeTokenBalances(dai, [owner, alice], [makingAmount, -makingAmount]);
await expect(tx).to.changeTokenBalances(weth, [owner, alice], [-takingAmount, takingAmount]);
});

it('extension 1 fill for 1 order via resolver with funds', async function () {
Expand Down Expand Up @@ -409,5 +417,64 @@ describe('MeasureGas', function () {
await expect(tx).to.changeTokenBalances(dai, [resolver, alice], [ether('100'), ether('-100')]);
await expect(tx).to.changeTokenBalances(weth, [owner, alice], [ether('-0.1'), ether('0.1')]);
});

it('extension 1 fill for 1 order with surplus', async function () {
const {
contracts: { dai, weth, lopv4, settlement },
accounts: { alice, bob, owner },
others: { chainId },
} = await loadFixture(initContractsForSettlement);
const now = await time.latest();
const makingAmount = ether('100');
const takingAmount = ether('0.1');
const auction = await buildAuctionDetails({ startTime: now, delay: 60, initialRateBump: 1000000n });
const surplus = ether('0.01'); // maximum auction bump rate

const orderData = {
maker: alice.address,
receiver: await settlement.getAddress(),
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits(),
};

const order = buildOrder(
orderData,
buildSettlementExtensions({
feeTaker: await settlement.getAddress(),
protocolFeeRecipient: bob.address,
estimatedTakingAmount: takingAmount,
getterExtraPrefix: auction.details,
whitelistPostInteraction: '0x0000000000',
protocolSurplusFee: 50,
}),
);

const { r, yParityAndS: vs } = ethers.Signature.from(await signOrder(order, chainId, await lopv4.getAddress(), alice));

const takerTraits = buildTakerTraits({
makingAmount: true,
threshold: takingAmount + surplus,
extension: order.extension,
});

await weth.approve(lopv4, takingAmount + surplus);

const tx = await lopv4.fillOrderArgs(
order,
r,
vs,
makingAmount,
takerTraits.traits,
takerTraits.args,
);

console.log(`1 fill for 1 order (surplus) gasUsed: ${(await tx.wait()).gasUsed}`);

await expect(tx).to.changeTokenBalances(dai, [owner, alice], [makingAmount, -makingAmount]);
await expect(tx).to.changeTokenBalances(weth, [owner, alice], [-takingAmount - surplus, takingAmount + surplus / 2n]);
});
});
});
12 changes: 8 additions & 4 deletions test/PriorityFeeLimiter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const { expect, deployContract, ether, constants } = require('@1inch/solidity-utils');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { buildOrder, buildMakerTraits, buildFeeTakerExtensions } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');
const { buildOrder, buildMakerTraits } = require('@1inch/limit-order-protocol-contract/test/helpers/orderUtils');
const { initContractsForSettlement } = require('./helpers/fixtures');
const { buildSettlementExtensions } = require('./helpers/fusionUtils');
const hre = require('hardhat');
const { network } = hre;

Expand All @@ -17,9 +18,12 @@ describe('PriorityFeeLimiter', function () {
async function prepare() {
const { contracts: { dai, weth, accessToken }, accounts: { owner } } = await initContractsForSettlement();
const settlementExtension = await deployContract('Settlement', [owner, weth, accessToken, weth, owner]);
const makingAmount = ether('10');
const takingAmount = ether('1');

const extensions = buildFeeTakerExtensions({
const extensions = buildSettlementExtensions({
feeTaker: await settlementExtension.getAddress(),
estimatedTakingAmount: takingAmount,
whitelistPostInteraction: '0x0000000000',
});

Expand All @@ -28,8 +32,8 @@ describe('PriorityFeeLimiter', function () {
maker: owner.address,
makerAsset: await dai.getAddress(),
takerAsset: await weth.getAddress(),
makingAmount: ether('10'),
takingAmount: ether('1'),
makingAmount,
takingAmount,
makerTraits: buildMakerTraits(),
},
extensions,
Expand Down
Loading