Skip to content

Commit

Permalink
feat: gas optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
RamboGj committed Nov 19, 2024
1 parent a3a303e commit cca7ae3
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 11 deletions.
10 changes: 10 additions & 0 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FundMeTest:testAddsFunderToArrayOfFunders() (gas: 98086)
FundMeTest:testCheaperWithdrawFromMultipleFunders() (gas: 484620)
FundMeTest:testFundFailsWithoutEnoughEth() (gas: 20851)
FundMeTest:testFundUpdatesFundedDataStructure() (gas: 97749)
FundMeTest:testMinimumDollarIsFive() (gas: 8445)
FundMeTest:testOnlyOwnerCanWithdraw() (gas: 97909)
FundMeTest:testOwnerIsMessageSender() (gas: 11301)
FundMeTest:testPriceFeedVersionIsAccurate() (gas: 11538)
FundMeTest:testWithdarawWithASingleFunder() (gas: 83425)
FundMeTest:testWithdrawFromMultipleFunders() (gas: 484601)
52 changes: 42 additions & 10 deletions src/FundMe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ error FundMe_NotOwner();
contract FundMe {
using PriceConverter for uint256;

mapping(address => uint256) public addressToAmountFunded;
address[] public funders;
mapping(address => uint256) private s_addressToAmountFunded;
address[] private s_funders;

// Could we make this constant? /* hint: no! We should make it immutable! */
address public immutable i_owner;
address private immutable i_owner;
uint256 public constant MINIMUM_USD = 5 * 10 ** 18;
AggregatorV3Interface private immutable s_priceFeed;

Expand All @@ -29,8 +28,8 @@ contract FundMe {
"You need to spend more ETH!"
);
// require(PriceConverter.getConversionRate(msg.value) >= MINIMUM_USD, "You need to spend more ETH!");
addressToAmountFunded[msg.sender] += msg.value;
funders.push(msg.sender);
s_addressToAmountFunded[msg.sender] += msg.value;
s_funders.push(msg.sender);
}

function getVersion() public view returns (uint256) {
Expand All @@ -43,16 +42,31 @@ contract FundMe {
_;
}

function cheaperWithdraw() public onlyOwner {
uint256 fundersLength = s_funders.length;

for (
uint256 funderIndex = 0;
funderIndex < fundersLength;
funderIndex++
) {
address funder = s_funders[funderIndex];
s_addressToAmountFunded[funder] = 0;
}

s_funders = new address[](0);
}

function withdraw() public onlyOwner {
for (
uint256 funderIndex = 0;
funderIndex < funders.length;
funderIndex < s_funders.length;
funderIndex++
) {
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
address funder = s_funders[funderIndex];
s_addressToAmountFunded[funder] = 0;
}
funders = new address[](0);
s_funders = new address[](0);
// // transfer
// payable(msg.sender).transfer(address(this).balance);

Expand Down Expand Up @@ -86,6 +100,24 @@ contract FundMe {
receive() external payable {
fund();
}

/*
View / Pure functions (Getters)
*/

function getAddressToAmountFunded(
address addr
) external view returns (uint256) {
return s_addressToAmountFunded[addr];
}

function getFunder(uint256 index) external view returns (address) {
return s_funders[index];
}

function getOwner() external view returns (address) {
return i_owner;
}
}

// Concepts we didn't cover yet (will cover in later sections)
Expand Down
111 changes: 110 additions & 1 deletion test/FundMeTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,21 @@ import {DeployFundMe} from "../script/DeployFundMe.s.sol";

contract FundMeTest is Test {
FundMe fundMe;
address USER = makeAddr("me");
uint256 constant SEND_VALUE = 0.1 ether;
uint256 constant STARTING_BALANCE = 10 ether;
uint256 constant GAS_PRICE = 1;

modifier funded() {
vm.prank(USER); // prank -> The next TX is gonna be sent by USER
fundMe.fund{value: SEND_VALUE}();
_;
}

function setUp() external {
DeployFundMe deployFundMe = new DeployFundMe();
fundMe = deployFundMe.run();
vm.deal(USER, STARTING_BALANCE);
}

function testMinimumDollarIsFive() public {
Expand All @@ -19,11 +30,109 @@ contract FundMeTest is Test {

function testOwnerIsMessageSender() public {
console.log(address(this));
assertEq(fundMe.i_owner(), msg.sender);
assertEq(fundMe.getOwner(), msg.sender);
}

function testPriceFeedVersionIsAccurate() public {
uint256 version = fundMe.getVersion();
assertEq(version, 4);
}

function testFundFailsWithoutEnoughEth() public {
vm.expectRevert(); // next line should revert
fundMe.fund();
}

function testFundUpdatesFundedDataStructure() public funded {
uint256 amountFunded = fundMe.getAddressToAmountFunded(USER);
assertEq(amountFunded, SEND_VALUE);
}

function testAddsFunderToArrayOfFunders() public funded {
address funder = fundMe.getFunder(0);
assertEq(funder, USER);
}

function testOnlyOwnerCanWithdraw() public funded {
vm.expectRevert();
vm.prank(USER);
fundMe.withdraw();
}

function testWithdarawWithASingleFunder() public funded {
// Arrange
uint256 startingOwnerBalance = fundMe.getOwner().balance;
uint256 startingFundMeBalance = address(fundMe).balance;

// Act
vm.prank(fundMe.getOwner());
fundMe.withdraw();

// Assert
uint256 endingOwnerBalance = fundMe.getOwner().balance;
uint256 endingFundMeBalance = address(fundMe).balance;
assertEq(endingFundMeBalance, 0);
assertEq(
startingFundMeBalance + startingOwnerBalance,
endingOwnerBalance
);
}

function testWithdrawFromMultipleFunders() public funded {
// Arrange
uint160 numberOfFunders = 10; // we need to use uint160 because it has the same amount of btyes than an address. This way we can create a new address()
uint160 startingFunderIndex = 1;

for (uint160 i = startingFunderIndex; i < numberOfFunders; i++) {
// vm.prank
// vm.deal
// fund fundMe
// hoax does the same as prank, the difference is that you can add some balance to the address on the second parameter.
hoax(address(i), SEND_VALUE);
fundMe.fund{value: SEND_VALUE}();
}

uint256 startingOwnerBalance = fundMe.getOwner().balance;
uint256 startingFundMeBalance = address(fundMe).balance;

// Act
vm.startPrank(fundMe.getOwner());
fundMe.withdraw();
vm.stopPrank();

assert(address(fundMe).balance == 0);
assert(
startingFundMeBalance + startingOwnerBalance ==
fundMe.getOwner().balance
);
}

function testCheaperWithdrawFromMultipleFunders() public funded {
// Arrange
uint160 numberOfFunders = 10; // we need to use uint160 because it has the same amount of btyes than an address. This way we can create a new address()
uint160 startingFunderIndex = 1;

for (uint160 i = startingFunderIndex; i < numberOfFunders; i++) {
// vm.prank
// vm.deal
// fund fundMe
// hoax does the same as prank, the difference is that you can add some balance to the address on the second parameter.
hoax(address(i), SEND_VALUE);
fundMe.fund{value: SEND_VALUE}();
}

uint256 startingOwnerBalance = fundMe.getOwner().balance;
uint256 startingFundMeBalance = address(fundMe).balance;

// Act
vm.startPrank(fundMe.getOwner());
fundMe.withdraw();
vm.stopPrank();

assert(address(fundMe).balance == 0);
assert(
startingFundMeBalance + startingOwnerBalance ==
fundMe.getOwner().balance
);
}
}

0 comments on commit cca7ae3

Please sign in to comment.