From 530df5a11cafcc750b8977b3c2266ff48a995024 Mon Sep 17 00:00:00 2001 From: malteish Date: Tue, 27 Jun 2023 21:46:33 +0200 Subject: [PATCH 1/4] add test that does not work with yul --- foundry.toml | 9 ++++++++- lib/forge-std | 2 +- test/Yul.t.sol | 21 +++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 test/Yul.t.sol diff --git a/foundry.toml b/foundry.toml index 2bc811e7..95913442 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,9 +2,16 @@ fuzz-runs = 10_000 [profile.default] -# via-ir = true # Enable the IR-based optimizer (yul) +via-ir = true # Enable the IR-based optimizer (yul) optimizer = true optimizer_runs = 10_000 +bytecode_hash = "none" # prevents compiler from attaching bytecode hash to contract metadata + +[profile.fastDev] +via-ir = false # Enable the IR-based optimizer (yul) +optimizer = true +optimizer_runs = 10_000 + gas_reports = ["AllowList", "ContinuousFundraising", "FeeSettings", "PersonalInvite", "PersonalInviteFactory", "Token"] [rpc_endpoints] diff --git a/lib/forge-std b/lib/forge-std index 066ff16c..e8a047e3 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 066ff16c5c03e6f931cd041fd366bc4be1fae82a +Subproject commit e8a047e3f40f13fa37af6fe14e6e06283d9a060e diff --git a/test/Yul.t.sol b/test/Yul.t.sol new file mode 100644 index 00000000..e0975676 --- /dev/null +++ b/test/Yul.t.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.13; + +import "../lib/forge-std/src/Test.sol"; + +contract YulTest is Test { + function setUp() public {} + + function testYul() public { + uint256 time = block.timestamp; + assertTrue(time == 1, "time is not 1 at the beginning"); + console.log("stored time before: ", time); + // problem: using yul, this warp changes the contents of the "time" variable + vm.warp(2 hours); + console.log("stored time after: ", time); + + // this test does not fail for some reason + assertTrue(time == 1, "time is not 1 after warp"); + assertTrue(time == 7200, "time is not 7200 after warp"); + } +} From 016aa65877eca8f0ebbead8391d8b0cfdab8036e Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 28 Jun 2023 12:05:28 +0200 Subject: [PATCH 2/4] fix first test for yul pipeline --- test/ContinuousFundraising.t.sol | 51 +++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/test/ContinuousFundraising.t.sol b/test/ContinuousFundraising.t.sol index c51dcad9..ccfb6ef0 100644 --- a/test/ContinuousFundraising.t.sol +++ b/test/ContinuousFundraising.t.sol @@ -732,19 +732,32 @@ contract ContinuousFundraisingTest is Test { /* try to unpause too soon after setMaxAmountOfTokenToBeSold */ - function testFailUnpauseTooSoonAfterSetMaxAmountOfTokenToBeSold() public { - uint256 time = block.timestamp; - vm.warp(time); + function testUnpauseTooSoonAfterSetMaxAmountOfTokenToBeSold( + uint128 startTime, + uint32 changeDelay, + uint32 attemptUnpauseDelay + ) public { + uint256 unpauseDelay = raise.delay(); + vm.assume(startTime < type(uint128).max / 2); + vm.assume(startTime > 0); + vm.assume(changeDelay > 0); + vm.assume(attemptUnpauseDelay > 0); + vm.assume(attemptUnpauseDelay < unpauseDelay + changeDelay); + + vm.warp(startTime); vm.prank(owner); raise.pause(); - assertTrue(raise.paused()); - assertTrue(raise.coolDownStart() == time); - vm.warp(time + 2 hours); + assertTrue(raise.paused(), "raise should be paused"); + assertTrue(raise.coolDownStart() == startTime, "coolDownStart should be startTime"); + vm.warp(startTime + changeDelay); vm.prank(owner); raise.setMaxAmountOfTokenToBeSold(700); - assertTrue(raise.coolDownStart() == time + 2 hours); - vm.warp(time + raise.delay() + 1 seconds); + assertTrue(raise.coolDownStart() == startTime + changeDelay, "coolDownStart should be startTime + changeDelay"); + vm.warp(startTime + attemptUnpauseDelay); vm.prank(owner); + console.log("current time: ", block.timestamp); + console.log("unpause at: ", startTime + changeDelay + unpauseDelay); + vm.expectRevert("There needs to be at minimum one day to change parameters"); raise.unpause(); // must fail because of the parameter update } @@ -770,18 +783,34 @@ contract ContinuousFundraisingTest is Test { /* try to unpause too soon after setCurrencyReceiver */ - function testFailUnpauseTooSoonAfterSetCurrencyReceiver() public { + function testUnpauseTooSoonAfterSetCurrencyReceiver() public { uint256 time = block.timestamp; vm.warp(time); vm.prank(owner); raise.pause(); + assertTrue(raise.paused()); assertTrue(raise.coolDownStart() == time); - vm.warp(time + 2 hours); + + // problem: using yul, this warp changes the contents of the "time" variable + console.log("stored time 1: ", time); + uint256 warpTo = 2 hours + time; + //vm.warp(time + 2 hours); + vm.warp(warpTo); + console.log("stored time 2: ", time); + + console.log("cooldown start at: ", raise.coolDownStart()); vm.prank(owner); raise.setCurrencyReceiver(payable(address(buyer))); assertTrue(raise.coolDownStart() == time + 2 hours); - vm.warp(time + raise.delay() + 1 hours); + console.log("cooldown start: ", raise.coolDownStart()); + console.log("delay: ", raise.delay()); + console.log("24 hours: ", 24 hours); + console.log("cooldown end: ", raise.coolDownStart() + raise.delay()); + //uint256 timeshift = 24 hours; + vm.warp(26 hours + 1); + console.log("current time: ", block.timestamp); + vm.expectRevert("There needs to be at minimum one day to change parameters"); vm.prank(owner); raise.unpause(); // must fail because of the parameter update } From b9875af8aea7de24a52fb13cc8733d4cf9ed3852 Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 28 Jun 2023 12:25:34 +0200 Subject: [PATCH 3/4] update tests to work with yul --- test/ContinuousFundraising.t.sol | 166 +++++++++++++++++++++---------- test/Yul.t.sol | 21 ---- 2 files changed, 115 insertions(+), 72 deletions(-) delete mode 100644 test/Yul.t.sol diff --git a/test/ContinuousFundraising.t.sol b/test/ContinuousFundraising.t.sol index ccfb6ef0..e8463e8b 100644 --- a/test/ContinuousFundraising.t.sol +++ b/test/ContinuousFundraising.t.sol @@ -783,35 +783,34 @@ contract ContinuousFundraisingTest is Test { /* try to unpause too soon after setCurrencyReceiver */ - function testUnpauseTooSoonAfterSetCurrencyReceiver() public { - uint256 time = block.timestamp; - vm.warp(time); + function testUnpauseTooSoonAfterSetCurrencyReceiver( + uint128 startTime, + uint32 changeDelay, + uint32 attemptUnpauseDelay, + address newCurrencyReceiver + ) public { + uint256 unpauseDelay = raise.delay(); + vm.assume(startTime < type(uint128).max / 2); + vm.assume(startTime > 0); + vm.assume(changeDelay > 0); + vm.assume(attemptUnpauseDelay > 0); + vm.assume(attemptUnpauseDelay < unpauseDelay + changeDelay); + vm.assume(newCurrencyReceiver != address(0)); + + vm.warp(startTime); vm.prank(owner); raise.pause(); - - assertTrue(raise.paused()); - assertTrue(raise.coolDownStart() == time); - - // problem: using yul, this warp changes the contents of the "time" variable - console.log("stored time 1: ", time); - uint256 warpTo = 2 hours + time; - //vm.warp(time + 2 hours); - vm.warp(warpTo); - console.log("stored time 2: ", time); - - console.log("cooldown start at: ", raise.coolDownStart()); + assertTrue(raise.paused(), "raise should be paused"); + assertTrue(raise.coolDownStart() == startTime, "coolDownStart should be startTime"); + vm.warp(startTime + changeDelay); + vm.prank(owner); + raise.setCurrencyReceiver(newCurrencyReceiver); + assertTrue(raise.coolDownStart() == startTime + changeDelay, "coolDownStart should be startTime + changeDelay"); + vm.warp(startTime + attemptUnpauseDelay); vm.prank(owner); - raise.setCurrencyReceiver(payable(address(buyer))); - assertTrue(raise.coolDownStart() == time + 2 hours); - console.log("cooldown start: ", raise.coolDownStart()); - console.log("delay: ", raise.delay()); - console.log("24 hours: ", 24 hours); - console.log("cooldown end: ", raise.coolDownStart() + raise.delay()); - //uint256 timeshift = 24 hours; - vm.warp(26 hours + 1); console.log("current time: ", block.timestamp); + console.log("unpause at: ", startTime + changeDelay + unpauseDelay); vm.expectRevert("There needs to be at minimum one day to change parameters"); - vm.prank(owner); raise.unpause(); // must fail because of the parameter update } @@ -837,19 +836,35 @@ contract ContinuousFundraisingTest is Test { /* try to unpause too soon after setMinAmountPerBuyer */ - function testFailUnpauseTooSoonAfterSetMinAmountPerBuyer() public { - uint256 time = block.timestamp; - vm.warp(time); + function testUnpauseTooSoonAfterSetMinAmountPerBuyer( + uint128 startTime, + uint32 changeDelay, + uint32 attemptUnpauseDelay, + uint256 newMinAmountPerBuyer + ) public { + uint256 unpauseDelay = raise.delay(); + vm.assume(startTime < type(uint128).max / 2); + vm.assume(startTime > 0); + vm.assume(changeDelay > 0); + vm.assume(attemptUnpauseDelay > 0); + vm.assume(attemptUnpauseDelay < unpauseDelay + changeDelay); + vm.assume(newMinAmountPerBuyer > 0); + vm.assume(newMinAmountPerBuyer <= raise.maxAmountPerBuyer()); + + vm.warp(startTime); vm.prank(owner); raise.pause(); - assertTrue(raise.paused()); - assertTrue(raise.coolDownStart() == time); - vm.warp(time + 2 hours); + assertTrue(raise.paused(), "raise should be paused"); + assertTrue(raise.coolDownStart() == startTime, "coolDownStart should be startTime"); + vm.warp(startTime + changeDelay); vm.prank(owner); - raise.setMinAmountPerBuyer(700); - assertTrue(raise.coolDownStart() == time + 2 hours); - vm.warp(time + raise.delay() + 1 hours); + raise.setMinAmountPerBuyer(newMinAmountPerBuyer); + assertTrue(raise.coolDownStart() == startTime + changeDelay, "coolDownStart should be startTime + changeDelay"); + vm.warp(startTime + attemptUnpauseDelay); vm.prank(owner); + console.log("current time: ", block.timestamp); + console.log("unpause at: ", startTime + changeDelay + unpauseDelay); + vm.expectRevert("There needs to be at minimum one day to change parameters"); raise.unpause(); // must fail because of the parameter update } @@ -875,19 +890,34 @@ contract ContinuousFundraisingTest is Test { /* try to unpause too soon after setMaxAmountPerBuyer */ - function testFailUnpauseTooSoonAfterSetMaxAmountPerBuyer() public { - uint256 time = block.timestamp; - vm.warp(time); + function testUnpauseTooSoonAfterSetMaxAmountPerBuyer( + uint128 startTime, + uint32 changeDelay, + uint32 attemptUnpauseDelay, + uint256 newMaxAmountPerBuyer + ) public { + uint256 unpauseDelay = raise.delay(); + vm.assume(startTime < type(uint128).max / 2); + vm.assume(startTime > 0); + vm.assume(changeDelay > 0); + vm.assume(attemptUnpauseDelay > 0); + vm.assume(attemptUnpauseDelay < unpauseDelay + changeDelay); + vm.assume(newMaxAmountPerBuyer >= raise.minAmountPerBuyer()); + + vm.warp(startTime); vm.prank(owner); raise.pause(); - assertTrue(raise.paused()); - assertTrue(raise.coolDownStart() == time); - vm.warp(time + 2 hours); + assertTrue(raise.paused(), "raise should be paused"); + assertTrue(raise.coolDownStart() == startTime, "coolDownStart should be startTime"); + vm.warp(startTime + changeDelay); vm.prank(owner); - raise.setMaxAmountPerBuyer(700); - assertTrue(raise.coolDownStart() == time + 2 hours); - vm.warp(time + raise.delay() + 1 hours); + raise.setMaxAmountPerBuyer(newMaxAmountPerBuyer); + assertTrue(raise.coolDownStart() == startTime + changeDelay, "coolDownStart should be startTime + changeDelay"); + vm.warp(startTime + attemptUnpauseDelay); vm.prank(owner); + console.log("current time: ", block.timestamp); + console.log("unpause at: ", startTime + changeDelay + unpauseDelay); + vm.expectRevert("There needs to be at minimum one day to change parameters"); raise.unpause(); // must fail because of the parameter update } @@ -910,22 +940,56 @@ contract ContinuousFundraisingTest is Test { raise.unpause(); } + // /* + // try to unpause too soon after setCurrencyAndTokenPrice + // */ + // function testUnpauseTooSoonAfterSetCurrencyAndTokenPrice() public { + // uint256 time = block.timestamp; + // vm.warp(time); + // vm.prank(owner); + // raise.pause(); + // assertTrue(raise.paused()); + // assertTrue(raise.coolDownStart() == time); + // vm.warp(time + 2 hours); + // vm.prank(owner); + // raise.setCurrencyAndTokenPrice(paymentToken, 700); + // assertTrue(raise.coolDownStart() == time + 2 hours); + // vm.warp(time + raise.delay() + 1 hours); + // vm.prank(owner); + // vm.expectRevert("There needs to be at minimum one day to change parameters"); + // raise.unpause(); // must fail because of the parameter update + // } + /* try to unpause too soon after setCurrencyAndTokenPrice */ - function testUnpauseTooSoonAfterSetCurrencyAndTokenPrice() public { - uint256 time = block.timestamp; - vm.warp(time); + function testUnpauseTooSoonAfterSetCurrencyAndTokenPrice( + uint128 startTime, + uint32 changeDelay, + uint32 attemptUnpauseDelay, + uint256 newTokenPrice + ) public { + uint256 unpauseDelay = raise.delay(); + vm.assume(startTime < type(uint128).max / 2); + vm.assume(startTime > 0); + vm.assume(changeDelay > 0); + vm.assume(attemptUnpauseDelay > 0); + vm.assume(attemptUnpauseDelay < unpauseDelay + changeDelay); + vm.assume(newTokenPrice > 0); + + vm.warp(startTime); vm.prank(owner); raise.pause(); - assertTrue(raise.paused()); - assertTrue(raise.coolDownStart() == time); - vm.warp(time + 2 hours); + assertTrue(raise.paused(), "raise should be paused"); + assertTrue(raise.coolDownStart() == startTime, "coolDownStart should be startTime"); + vm.warp(startTime + changeDelay); vm.prank(owner); - raise.setCurrencyAndTokenPrice(paymentToken, 700); - assertTrue(raise.coolDownStart() == time + 2 hours); - vm.warp(time + raise.delay() + 1 hours); + raise.setCurrencyAndTokenPrice(paymentToken, newTokenPrice); + assertTrue(raise.coolDownStart() == startTime + changeDelay, "coolDownStart should be startTime + changeDelay"); + vm.warp(startTime + attemptUnpauseDelay); vm.prank(owner); + console.log("current time: ", block.timestamp); + console.log("unpause at: ", startTime + changeDelay + unpauseDelay); vm.expectRevert("There needs to be at minimum one day to change parameters"); raise.unpause(); // must fail because of the parameter update } diff --git a/test/Yul.t.sol b/test/Yul.t.sol deleted file mode 100644 index e0975676..00000000 --- a/test/Yul.t.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity ^0.8.13; - -import "../lib/forge-std/src/Test.sol"; - -contract YulTest is Test { - function setUp() public {} - - function testYul() public { - uint256 time = block.timestamp; - assertTrue(time == 1, "time is not 1 at the beginning"); - console.log("stored time before: ", time); - // problem: using yul, this warp changes the contents of the "time" variable - vm.warp(2 hours); - console.log("stored time after: ", time); - - // this test does not fail for some reason - assertTrue(time == 1, "time is not 1 after warp"); - assertTrue(time == 7200, "time is not 7200 after warp"); - } -} From 1910bb605b4531815fb430f091260455b6eb2143 Mon Sep 17 00:00:00 2001 From: malteish Date: Fri, 7 Jul 2023 13:04:01 +0200 Subject: [PATCH 4/4] update hh config to use yul pipeline --- foundry.toml | 1 - hardhat.config.ts | 49 +++++++++++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/foundry.toml b/foundry.toml index 95913442..b8878bcf 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,7 +4,6 @@ fuzz-runs = 10_000 [profile.default] via-ir = true # Enable the IR-based optimizer (yul) optimizer = true -optimizer_runs = 10_000 bytecode_hash = "none" # prevents compiler from attaching bytecode hash to contract metadata [profile.fastDev] diff --git a/hardhat.config.ts b/hardhat.config.ts index 903096b0..92bdad19 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,11 +1,11 @@ -import { HardhatUserConfig, task } from "hardhat/config"; +import { HardhatUserConfig, task } from 'hardhat/config'; -import "dotenv/config"; -import "hardhat-gas-reporter"; -import "@nomiclabs/hardhat-etherscan"; -import "@typechain/hardhat"; -import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-waffle"; +import 'dotenv/config'; +import 'hardhat-gas-reporter'; +import '@nomiclabs/hardhat-etherscan'; +import '@typechain/hardhat'; +import '@nomiclabs/hardhat-ethers'; +import '@nomiclabs/hardhat-waffle'; // require("@nomiclabs/hardhat-waffle"); // require("hardhat-gas-reporter"); @@ -14,7 +14,7 @@ import "@nomiclabs/hardhat-waffle"; // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { +task('accounts', 'Prints the list of accounts', async (taskArgs, hre) => { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { @@ -30,48 +30,59 @@ task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { */ const config: HardhatUserConfig = { solidity: { - version: "0.8.17", + version: '0.8.17', settings: { + // optimizer: { + // enabled: true, + // runs: 10000, + // }, + metadata: { + bytecodeHash: 'none', + }, + viaIR: true, optimizer: { enabled: true, - runs: 10000, + details: { + yulDetails: { + //optimizerSteps: 'u', // recommended by hh, but yields longer bytecode + }, + }, }, - // viaIR: true, // outputSelection: { "*": { "*": ["storageLayout"] } }, }, }, networks: { localhost: { - url: "http://localhost:8545", + url: 'http://localhost:8545', }, ropsten: { - url: process.env.ROPSTEN_URL || "", + url: process.env.ROPSTEN_URL || '', accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], }, goerli: { - url: process.env.GOERLI_RPC_URL || "", + url: process.env.GOERLI_RPC_URL || '', accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], }, mainnet: { - url: process.env.MAINNET_RPC_URL || "", + url: process.env.MAINNET_RPC_URL || '', accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], }, }, gasReporter: { enabled: process.env.REPORT_GAS !== undefined, - currency: "USD", + currency: 'USD', }, etherscan: { apiKey: process.env.ETHERSCAN_API_KEY, }, typechain: { - outDir: "types", - target: "ethers-v5", + outDir: 'types', + target: 'ethers-v5', alwaysGenerateOverloads: false, // should overloads with full signatures like deposit(uint256) be generated always, even if there are no overloads? - externalArtifacts: ["externalArtifacts/*.json"], // optional array of glob patterns with external artifacts to process (for example external libs from node_modules) + externalArtifacts: ['externalArtifacts/*.json'], // optional array of glob patterns with external artifacts to process (for example external libs from node_modules) dontOverrideCompile: false, // defaults to false }, };