Table of Contents
How to use Foundry with OpenZeppelin
forge init {ProjectName}
cd {ProjectName}
Install openzeppelin-contracts
:
forge install OpenZeppelin/openzeppelin-contracts
echo "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/" >> remmapings.txt
The project's structure should be:
.
├── README.md
├── foundry.toml
├── lib
│ ├── forge-std
│ └── openzeppelin-contracts
├── remmapings.txt
├── script
│ └── Counter.s.sol
├── src
│ └── Counter.sol
└── test
└── Counter.t.sol
We can replace all the occurrences of Counter
to Token
i.e:
.
├── README.md
├── foundry.toml
├── lib
│ ├── forge-std
│ └── openzeppelin-contracts
├── remmapings.txt
├── script
│ └── Token.s.sol
├── src
│ └── Token.sol
└── test
└── Token.t.sol
Then, inside Token.sol
, which is the main contract, the example from the OZ docs' can be used:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor(uint256 initialSupply) ERC20("Token", "TKN") {
// The deployer will have all the initialSupply
_mint(msg.sender, initialSupply);
}
}
Then we have to change the deployment script script/Token.s.sol
:
- Reference: Solidity Scripting - Foundry Book
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Script, console} from "forge-std/Script.sol";
import "../src/Token.sol";
contract TokenScript is Script {
uint256 deployerPrivateKey;
function setUp() public {
// foundry will read the env variable named PRIVATE_KEY
// and it will use it to deploy the contract
deployerPrivateKey = vm.envUint("PRIVATE_KEY");
}
function run() public {
vm.startBroadcast(deployerPrivateKey);
// This is the initialSupply the constructor will use
Token token = new Token(1000000);
vm.stopBroadcast();
}
}
For simplicity, the contract will be deployed in a local environment created with anvil
.
Run anvil
in a terminal, the output should be:
Available Accounts
==================
(0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000.000000000000000000 ETH)
.
.
Private Keys
==================
(0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
.
.
This funded account can be used to deploy the contract, with anvil
running, open a new terminal and run:
echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env
echo "ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" >> .env
Then, deploy the contract, forge
will automatically read the .env
file:
forge script script/Token.s.sol:TokenScript --rpc-url http:localhost:8545 --broadcast
Note: if using http:localhost:8545
, which is anvil's default port, the flag --rpc-url
is not necessary.
Finally, the output should contain the Contract Address
:
✅ [Success]Hash: 0x07ba8c8365d97fa68eef4d623fe5c1a91b7318dee6071b3c4e0de3b8a8e6551b
Contract Address: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Block: 1
Paid: 0.002214764 ETH (553691 gas * 4 gwei)
It can be used with cast
to ask for the erc20 balance
, the constructor of the Contract was defined to mint the initialSupply
to the deployer
address, and the initialSupply
was defined in the Token.s.sol
: Token token = new Token(1000000);
:
source .env
cast balance --erc20 0x5FbDB2315678afecb367f032d93F642f64180aa3 $ADDRESS --rpc-url http:localhost:8545
Output:
1000000 [1e6]