Skip to content

Commit

Permalink
batch update
Browse files Browse the repository at this point in the history
  • Loading branch information
terrancrypt committed Aug 19, 2024
1 parent 092689a commit 035676b
Show file tree
Hide file tree
Showing 18 changed files with 367 additions and 126 deletions.
5 changes: 5 additions & 0 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CrowdfundingTest:test_can_fund() (gas: 130013)
CrowdfundingTest:test_can_withdraw() (gas: 172928)
CrowdfundingTest:test_priceFeedSetCorrectly() (gas: 18677)
CrowdfundingTest:test_revert_fund() (gas: 21329)
CrowdfundingTest:test_revert_withdraw() (gas: 11406)
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
src = "src"
out = "out"
libs = ["lib"]
remappings = ["@chainlink=lib/chainlink"]
fs_permissions = [{ access = "read", path = "./broadcast" }]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
2 changes: 1 addition & 1 deletion lib/chainlink
Submodule chainlink updated 1902 files
2 changes: 1 addition & 1 deletion lib/foundry-devops
Submodule foundry-devops updated 1 files
+1 −1 README.md
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
18 changes: 18 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-include .env

ANVIL_PRIVATE_KEY := 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

NETWORK_ARGS := --rpc-url http://localhost:8545 --private-key $(ANVIL_PRIVATE_KEY) --broadcast

ifeq ($(findstring --network sepolia,$(ARGS)),--network sepolia)
NETWORK_ARGS := --rpc-url $(SEPOLIA_RPC_URL) --account $(ACCOUNT) --broadcast --verify --etherscan-api-key $(ETHERSCAN_API_KEY) -vvvv
endif

deploy:
@forge script script/DeployCrowdfunding.s.sol:DeployCrowdfunding $(NETWORK_ARGS)

fund:
@forge script script/Interactions.s.sol:FundCrowdfunding $(NETWORK_ARGS)

withdraw:
@forge script script/Interactions.s.sol:WithdrawCrowdfunding $(NETWORK_ARGS)
68 changes: 2 additions & 66 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,2 @@
## Foundry

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

https://book.getfoundry.sh/

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

### Cast

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
## Note
- Chainlink Package Version: v2.14.0
12 changes: 12 additions & 0 deletions script/Constants.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

abstract contract Constants {
uint8 public constant DECIMALS = 8;
int256 public constant INITIAL_PRICE = 2000e8;

// ========== Chain IDs ==========
uint256 public constant ETH_SEPOLIA_CHAIN_ID = 11155111;
uint256 public constant ZKSYNC_SEPOLIA_CHAIN_ID = 300;
uint256 public constant ANVIL_CHAIN_ID = 31337;
}
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

19 changes: 19 additions & 0 deletions script/DeployCrowdfunding.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Script} from "forge-std/Script.sol";
import {Crowdfunding} from "src/Crowdfunding.sol";
import {HelperConfig} from "script/HelperConfig.s.sol";

contract DeployCrowdfunding is Script {
function run() external returns (Crowdfunding, HelperConfig) {
HelperConfig helperConfig = new HelperConfig();
address priceFeed = helperConfig.getConfigByChainId(block.chainid).priceFeed;

vm.startBroadcast();
Crowdfunding crowdfunding = new Crowdfunding(priceFeed);
vm.stopBroadcast();

return (crowdfunding, helperConfig);
}
}
56 changes: 56 additions & 0 deletions script/HelperConfig.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Script} from "forge-std/Script.sol";
import {Constants} from "./Constants.sol";
import {MockV3Aggregator} from "@chainlink/contracts/src/v0.8/tests/MockV3Aggregator.sol";

contract HelperConfig is Constants, Script {
// ========== Errors ==========
error HelperConfig__InvalidChainId();

// ========== Types ==========
struct NetworkConfig {
address priceFeed;
}

// ========== State Variables ==========
NetworkConfig public localNetworkConfig;
mapping(uint256 chainId => NetworkConfig) public networkConfigs;

// ========== Functions ==========
constructor() {
networkConfigs[ETH_SEPOLIA_CHAIN_ID] = getSepoliaEthConfig();
}

function getConfigByChainId(uint256 chainId) public returns (NetworkConfig memory) {
if (networkConfigs[chainId].priceFeed != address(0)) {
return networkConfigs[chainId];
} else if (chainId == ANVIL_CHAIN_ID) {
return getOrCreateAnvilETHConfig();
} else {
revert HelperConfig__InvalidChainId();
}
}

// ========== On-Chain Configs ==========
function getSepoliaEthConfig() public pure returns (NetworkConfig memory) {
return NetworkConfig({
priceFeed: 0x694AA1769357215DE4FAC081bf1f309aDC325306 // ETH/USD
});
}

// ========== Local Config ==========
function getOrCreateAnvilETHConfig() public returns (NetworkConfig memory) {
if (localNetworkConfig.priceFeed != address(0)) {
return localNetworkConfig;
}

vm.startBroadcast();
MockV3Aggregator mockPriceFeed = new MockV3Aggregator(DECIMALS, INITIAL_PRICE);
vm.stopBroadcast();

localNetworkConfig = NetworkConfig({priceFeed: address(mockPriceFeed)});
return localNetworkConfig;
}
}
36 changes: 36 additions & 0 deletions script/Interactions.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Script, console} from "forge-std/Script.sol";
import {DevOpsTools} from "foundry-devops/src/DevOpsTools.sol";
import {Crowdfunding} from "src/Crowdfunding.sol";

contract FundCrowdfunding is Script {
uint256 SEND_VALUE = 0.1 ether;

function fundToCrowdfunding(address mostRecentlyDeployed) public {
vm.startBroadcast();
Crowdfunding(payable(mostRecentlyDeployed)).fund{value: SEND_VALUE}();
vm.stopBroadcast();
console.log("Funded to Crowdfunding with %s", SEND_VALUE);
}

function run() external {
address mostRecentlyDeployed = DevOpsTools.get_most_recent_deployment("Crowdfunding", block.chainid);
fundToCrowdfunding(mostRecentlyDeployed);
}
}

contract WithdrawCrowdfunding is Script {
function withdrawFromCrowdfunding(address mostRecentlyDeployed) public {
vm.startBroadcast();
Crowdfunding(payable(mostRecentlyDeployed)).withdraw();
vm.stopBroadcast();
console.log("Withdraw FundMe balance!");
}

function run() external {
address mostRecentlyDeployed = DevOpsTools.get_most_recent_deployment("Crowdfunding", block.chainid);
withdrawFromCrowdfunding(mostRecentlyDeployed);
}
}
14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

63 changes: 63 additions & 0 deletions src/Crowdfunding.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {PriceConverter} from "./lib/PriceConverter.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

contract Crowdfunding is Ownable {
using PriceConverter for address;

error InsufficientFunding();

uint256 public constant MINIMUM_USD = 5e18; // 5 USD in Wei

mapping(address => bool) public s_isFunders;
mapping(address => uint256) public s_funderToAmount;
address[] public s_funders;

address public immutable i_ethPriceFeed;

event Funded(address indexed funder, uint256 value);
event Withdrawn(uint256 value);

receive() external payable {
fund();
}

fallback() external payable {
fund();
}

constructor(address ethPriceFeed) Ownable(msg.sender) {
i_ethPriceFeed = ethPriceFeed;
}

function fund() public payable {
if (i_ethPriceFeed.getConversionRate(msg.value) < MINIMUM_USD) {
revert InsufficientFunding();
}

s_funderToAmount[msg.sender] += msg.value;
bool isFunded = s_isFunders[msg.sender];

if (!isFunded) {
s_funders.push(msg.sender);
s_isFunders[msg.sender] = true;
}

emit Funded(msg.sender, msg.value);
}

function withdraw() public onlyOwner {
uint256 withdrawBal = address(this).balance;
(bool sent,) = payable(owner()).call{value: withdrawBal}("");
require(sent, "Failed to send Ether");

emit Withdrawn(withdrawBal);
}

function getETHPriceFeedVersion() public view returns (uint256) {
return AggregatorV3Interface(i_ethPriceFeed).version();
}
}
20 changes: 20 additions & 0 deletions src/lib/PriceConverter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

library PriceConverter {
function getPrice(address _priceFeed) internal view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(_priceFeed);
(, int256 answer,,,) = priceFeed.latestRoundData();
require(answer > 0, "Invalid price data");
// nhận về 8 digits, thêm vào 10 số 0 để lấy thành 18 digits
return uint256(answer) * 1e10;
}

function getConversionRate(address priceFeed, uint256 ethAmount) internal view returns (uint256) {
uint256 ethPrice = getPrice(priceFeed);
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1e18;
return ethAmountInUsd;
}
}
24 changes: 0 additions & 24 deletions test/Counter.t.sol

This file was deleted.

Loading

0 comments on commit 035676b

Please sign in to comment.