-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
bug(forge test
): --gas-report
does reporting certain contracts (assembled bytecode in constructor)
#6129
Comments
thanks for the repro will investigate |
@mattsse fyi some related issues: |
can you please explain what impact this has on the defined functions when used because I think if you do this then everything is inlined, right? so there's no actual call happening that we can track and decode |
Here's a deployed example with the functions called - |
I am running into a similar issue of ComponentForge Have you ensured that all of these are up to date?Foundry
OS:Linux What version of Foundry are you on?
What command(s) is the bug in?
Minimal Example
This passes but does not give a gas report
|
Running into the exact same issue as well. This is a bit annoying when running benchmarks (i.e. comparing to similar implementations). Right now, the two solutions are either to use Hardhat (which does indeed support "bytecode" contracts, or to log gas usage (with A third solution is this forge-gas-metering library, but it would currently only support a single call per test. It would be amazing to have this supported, especially as it seems to be one of the most efficient ways to optimize gas usage; hence my eagerness to be able to demonstrate it! Thanks. For reproduction:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
contract BytecodeDrop {
constructor() {
assembly {
mstore(0x00, 0x59351559341117600D57601A565B5959FD5B6000526004601CFD5B593560E01C)
mstore(0x20, 0x6382947ABE14602D575B3434FD5B602435600401604435600401808203813583)
mstore(0x40, 0x3581036055576004357F23b872dd000000000000000000000000000000000000)
mstore(0x60, 0x0000000000000000000034523360045230602452606435604452343460643434)
mstore(0x80, 0x855AF1156055577Fa9059cbb0000000000000000000000000000000000000000)
mstore(0xA0, 0x000000000000000034528160051B60200185018560015B906020018083031560)
mstore(0xC0, 0xDC5790813560045285820335602452343460443434885AF11660B6565B156055)
mstore(0xE0, 0x573434F300000000000000000000000000000000000000000000000000000000)
return(0x00, 0xE4)
}
}
/**
* @notice Airdrop ERC20 tokens to a list of addresses
* @param _token The address of the ERC20 contract
* @param _addresses The addresses to airdrop to
* @param _amounts The amounts to airdrop
* @param _totalAmount The total amount to airdrop
*/
function airdropERC20(
address _token,
address[] calldata _addresses,
uint256[] calldata _amounts,
uint256 _totalAmount
) external {}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {ERC20} from "@solady/tokens/ERC20.sol";
contract Mock_ERC20 is ERC20 {
constructor(uint256 _initialAmount) {
_mint(msg.sender, _initialAmount);
}
function name() public pure override returns (string memory) {
return "Mock_ERC20";
}
function symbol() public pure override returns (string memory) {
return "M20";
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {BytecodeDrop} from "src/BytecodeDrop.sol";
import {Mock_ERC20} from "test/mocks/Mock_ERC20.sol";
import {Test} from "forge-std/Test.sol";
contract BytecodeDropTest is Test {
BytecodeDrop bytecodeDrop;
Mock_ERC20 erc20;
uint256 constant NUM_RECIPIENTS = 2;
uint256 constant AMOUNT = 10e18;
uint256 constant TOTAL_AMOUNT = AMOUNT * NUM_RECIPIENTS;
constructor() {
bytecodeDrop = new BytecodeDrop();
erc20 = new Mock_ERC20(AMOUNT * 2);
}
function test_BytecodeDrop() public {
address[] memory addresses = new address[](NUM_RECIPIENTS);
uint256[] memory amounts = new uint256[](NUM_RECIPIENTS);
for (uint256 i = 0; i < NUM_RECIPIENTS; i++) {
addresses[i] = vm.addr(i + 1);
amounts[i] = AMOUNT;
}
erc20.approve(address(bytecodeDrop), TOTAL_AMOUNT);
bytecodeDrop.airdropERC20(address(erc20), addresses, amounts, AMOUNT * 2);
}
} Run the test: |
Test and setup functions are excluded from gas reports on purpose, see foundry/crates/forge/src/gas_report.rs Lines 94 to 96 in a2a6bcd
I guess this should be toggleable given the demand? |
forge test
): --gas-report
does reporting certain contracts (assembled bytecode in constructor)
I have the similar problem: bytecode imported from a json file, deployed via This forces me to use @mattsse , are there any estimates on when this is going to be supported? It is exactly a year since this was reported (interesting coincidence). |
Re:
by @DaniPopes and #9232 by @grandizzy I don't think the @mattsse gave a hint in his comment:
However, I am not sure if this is true given that the test contract DOES make an external call to the contract being tested... |
Component
Forge
Have you ensured that all of these are up to date?
What version of Foundry are you on?
forge 0.2.0 (a839414 2023-10-26T09:23:09.940495000Z)
What command(s) is the bug in?
forge test --gas-report
Operating System
Windows
Describe the bug
I am working on proof of concept custom bytecode contracts where all of the functions are stubbed out so that the contract can be compiled/verified on block explorers with a generated ABI but the runtime bytecode is assembled in the constructor based on constructor arguments.
Tests run successfully and report gas total gas consumption for the tests but when attempting to run the gas report there is no report generated for the contract.
I created an example project using the default Counters contract that follows the same design pattern being applied to the proof of concept contracts that I am working on. In the example the default Counters contract runs tests and generates a gas report as expected however the BytecodeCounters contract will run tests and not generate a gas report.
https://github.com/0xth0mas/foundry-bytecode-gas-report-example
The text was updated successfully, but these errors were encountered: