Foundry는 스마트 컨트랙트 개발을 위한 툴킷으로, 이더리움 블록체인에서 사용됩니다.
Foundry는 다음과 같은 구성 요소를 포함하고 있습니다
- Forge: 스마트 컨트랙트를 컴파일하고 테스트하기 위한 이더리움 개발 환경입니다.
- Cast: 이더리움 RPC API와 상호 작용하기 위한 CLI(Command-Line Interface) 도구입니다.
- Anvil: 로컬 테스트넷을 만들기 위한 도구로, 개발 중인 스마트 컨트랙트를 테스트할 수 있습니다.
Foundry의 주요 특징은 다음과 같습니다
- 빠른 컴파일 속도: Rust로 작성되어 컴파일 속도가 매우 빠릅니다.
- 유연한 테스팅: Solidity 스마트 컨트랙트를 위한 강력하고 유연한 테스트 프레임워크를 제공합니다.
- 사용 편의성: 사용하기 쉬운 인터페이스와 명령어로 구성되어 있습니다.
Installation
$ curl -L https://foundry.paradigm.xyz | bash
$ source ~/.bashrc
$ foundryup
Start Project with Foundry
Foundry의 기본 구조는 아래와 같습니다. 컨트랙트를 작성할 때는 src 밑에 작성하시면 됩니다.
$ forge init [project_name]
$ cd ./[project_name]
$ tree . -d -L 1
.
├── README.md
├── foundry.toml
├── lib
│ └── forge-std
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── foundry.toml
│ ├── package.json
│ ├── scripts
│ ├── src
│ └── test
├── script
│ └── Counter.s.sol
├── src # contract 기본 폴더
│ └── Counter.sol
└── test
└── Counter.t.sol
8 directories, 10 files
로컬 테스트넷
Anvil 로컬 테스트넷을 만들기 위한 도구로, 개발 중인 스마트 컨트랙트를 테스트할 수 있습니다.
기본 옵션은 10개의 account와 1000ETH, 블록은 요청이 있을 때 생성
$ anvil [options]
$ anvil
_ _
(_) | |
__ _ _ __ __ __ _ | |
/ _` | | '_ \ \ \ / / | | | |
| (_| | | | | | \ V / | | | |
\__,_| |_| |_| \_/ |_| |_|
0.2.0 (fd87888 2024-06-17T00:19:40.909161347Z)
https://github.com/foundry-rs/foundry
Available Accounts
==================
(0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000.000000000000000000 ETH)
(1) 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (10000.000000000000000000 ETH)
(2) 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC (10000.000000000000000000 ETH)
(3) 0x90F79bf6EB2c4f870365E785982E1f101E93b906 (10000.000000000000000000 ETH)
(4) 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 (10000.000000000000000000 ETH)
(5) 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc (10000.000000000000000000 ETH)
(6) 0x976EA74026E726554dB657fA54763abd0C3a0aa9 (10000.000000000000000000 ETH)
(7) 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 (10000.000000000000000000 ETH)
(8) 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f (10000.000000000000000000 ETH)
(9) 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 (10000.000000000000000000 ETH)
Private Keys
==================
(0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
(1) 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
(2) 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
(3) 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
(4) 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
(5) 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
(6) 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e
(7) 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356
(8) 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97
(9) 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
Wallet
==================
Mnemonic: test test test test test test test test test test test junk
Derivation path: m/44'/60'/0'/0/
Chain ID
==================
31337
Base Fee
==================
1000000000
Gas Limit
==================
30000000
Genesis Timestamp
==================
1718595526
Listening on 127.0.0.1:8545
컨트랙트 배포
1. 컨트랙트 작성
아래의 코드는 컨트랙트 배포를 학습하기 위한 샘플 코드입니다. 이 컨트랙트는 solved변수와 solve() 함수를 호출하면 solved 함수가 true가 되는 코드입니다.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Solve {
bool public solved;
function solve() external {
solved = true;
}
}
2. 컨트랙트 컴파일
$ forge build
3. 컨트랙트 배포
이번 배포는 테스트를 위해 Anvil 명령어를 통해 로컬 테스트넷을 만든 후 진행하였습니다. 컨트랙트를 배포하기 위해 anvil 명령을 실행하면 나오는 개인키중 하나와 rpc 주소를 지정하여 컨트랙트를 배포하시면 됩니다.
$ forge create [options] contract
$ forge create Solve \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--rpc-url 127.0.0.1:8545 \
컨트랙트와 상호작용
Cast는 이더리움 RPC API와 상호 작용하기 위한 CLI(Command-Line Interface) 도구입니다.
아래 명령은 위에서 배포한 컨트랙트의 solve() 함수를 호출하여 solved값을 true로 변경하는 과정입니다.
$ cast send --private-key [내 개인키] --rpc-url 127.0.0.1:8545 <컨트랙트 주소> "solve"
아래 명령은 위에서 호출한 solve() 함수를 통해 solved 변수가 true 바뀌었는지 확인하는 과정입니다.
$ cast call --rpc-url 127.0.0.1:8545 <컨트랙트 주소> "solved"
true
위 명령 두개를 통해 함수를 호출하고 값을 확인할 수 있습니다. 그런데 여기서 한가지 이상한 점이 있는데요. cast send에는 private-key를 사용하고 cast call은 private-key를 옵션으로 제공하지 않습니다. 그 이유는 두 개의 명령어가 목적이 다르기 때문입니다.
send vs call
Cast의 send와 call 명령은 모두 이더리움 블록체인에 트랜잭션을 보내는 데 사용되지만, 그 명령의 목적에는 약간의 차이가 있습니다.
- cast send:
- 트랜잭션을 블록체인에 제출하고 실행합니다.
- 트랜잭션이 성공적으로 처리되면 블록체인 상태가 변경됩니다.
- Gas를 소모하며, 트랜잭션 수수료가 발생합니다.
- 트랜잭션이 성공했는지 여부를 반환합니다.
- cast call:
- 블록체인 상태를 변경하지 않고 읽기 전용 작업을 수행합니다.
- 스마트 컨트랙트 함수를 로컬에서 실행하고 반환값을 확인하는 데 사용됩니다.
- Gas를 소모하지 않으며, 트랜잭션 수수료가 발생하지 않습니다.
- 스마트 컨트랙트 함수의 반환값을 출력합니다.
주요 차이점은 다음과 같습니다:
컨트랙트 상태 변경 | Gas 소모 | 반환값 | |
send | O | O | 트랜잭션 성공 여부 |
call | X | X | 호출한 함수의 반환값 |
따라서 블록체인 상태를 변경해야 하는 경우에는 send를, 스마트 컨트랙트 함수의 동작을 확인하고 반환값을 보고 싶은 경우에는 call을 사용하는 것이 일반적입니다.