Foundry로 스마트 컨트랙트 배포하기
소개
Foundry는 개발자가 Solidity 스크립트를 통해 명령줄에서 컨트랙트를 관리 및 컴파일하고, 테스트를 실행하고, 컨트랙트를 배포하고, 네트워크와 상호작용할 수 있도록 지원하는 Rust로 작성된 스마트 컨트랙트 개발 프레임워크입니다.
Foundry는 빠르고 모듈화된 스마트 컨트랙트 개발을 가능하게 하는 네 가지 주요 CLI 도구로 구성되어 있습니다:
- Forge: Forge를 사용하여 스마트 컨트랙트를 배포, 테스트 및 컴파일할 수 있습니다.
- Cast: 캐스트는 EVM 스마트 컨트랙트와의 상호작용을 간단하게 만들어줍니다. 여기에는 체인 데이터 가져오기, 트랜잭션 전송 등이 포함됩니다.
- Anvil: 로컬 노드를 스핀업해야 하나요? Anvil은 Foundry에서 제공하는 로컬 노드 환경입니다.
- Chisel: 빠르고 유용하며 자세한 Solidity REPL.
이 가이드에서는 다음을 수행합니다:
- 간단한 Foundry 프로젝트를 생성합니다.
- Foundry를 사용하여 스마트 컨트랙트 샘플을 컴파일하고 테스트합니다.
- Foundry를 사용하여 스마트 컨트랙트를 클레이튼 Baobab 네트워크에 배포합니다.
- Cast와 Anvil로 메인넷 포크 살펴보기.
사전 요구 사항
이 튜토리얼을 따르기 위한 전제 조건은 다음과 같습니다:
- 코드 편집기: VS-Code와 같은 소스 코드 편집기.
- MetaMask: 컨트랙트를 배포하고, 트랜잭션에 서명하고, 컨트랙트와 상호 작용하는 데 사용됩니다.
- RPC 엔드포인트: 지원되는 엔드포인트 공급자 중 하나에서 얻을 수 있습니다.
- Faucet에서 KLAY 테스트: 충분한 KLAY로 계정에 자금을 충전합니다.
- Rust 및 Foundry를 설치합니다.
개발 환경 설정하기
Foundry 설치가 성공적으로 완료되었는지 확인하려면 아래 명령을 실행하세요:
forge -V
출력
Foundry를 성공적으로 설치했으면 이제 Foundry에서 사용할 수 있는 CLI 도구(forge, cast, anvil, chisel)에 액세스할 수 있습니다. 다음 단계에 따라 Foundry 프로젝트를 설정해 보겠습니다:
1단계: 새 프로젝트를 시작하려면 아래 명령을 실행합니다:
forge init foundry_example
2단계: 프로젝트 폴더로 이동합니다.
cd foundry_examplels
Foundry 프로젝트를 초기화한 후, 현재 디렉터리에 다음이 포함되어야 합니다:
- src: 스마트 컨트랙트의 기본 디렉터리입니다.
- tests: 테스트를 위한 기본 디렉터리.
- foundry.toml: 기본 프로젝트 구성 파일.
- lib: 프로젝트 종속성을 위한 기본 디렉터리.
- script: Solidity 스크립팅 파일의 기 본 디렉터리.
스마트 컨트랙트 샘플
이 섹션에서는 초기화된 Foundry 프로젝트에서 샘플 카운터 컨트랙트를 사용하겠습니다. src/
폴더의 counter.sol
파일은 다음과 같은 모습이어야 합니다:
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;contract Counter { uint256 public number; function setNumber(uint256 newNumber) public { number = newNumber; } function increment() public { number++; }}
코드 연습
이것이 여러분의 스마트 컨트랙트입니다. 1행은 Solidity 버전 0.8.13 이상을 사용함을 보여줍니다. 4줄부터 12줄까지는 스마트 컨트랙트 Counter
가 생성됩니다. 이 컨트랙트는 setNumber 함수를 사용하여 새로운 숫자를 저장하고 increment 함수를 호출하여 숫자를 증가시킵니다.
스마트 컨트랙트 테스트
Foundry를 사용하면 다른 스마트 컨트랙트 개발 프레임워크에서 JavaScript로 테스트를 작성하는 것과 달리 Solidity로 테스트를 작성할 수 있습니다. 초기화된 Foundry 프로젝트에서 test/Counter.t.sol
은 Solidity로 작성된 테스트의 예시입니다. 코드는 다음과 같습니다:
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;import "forge-std/Test.sol";import "../src/Counter.sol";contract CounterTest is Test { Counter public counter; function setUp() public { counter = new Counter(); counter.setNumber(0); } function testIncrement() public { counter.increment(); assertEq(counter.number(), 1); } function testSetNumber(uint256 x) public { counter.setNumber(x); assertEq(counter.number(), x); }}
위 코드는 위조 표준 라이브러리와 Counter.sol을 가져온 것을 보여줍니다.
위의 테스트는 다음을 확인합니다:
- 숫자가 증가하고 있는가?
- 숫자가 설정된 숫자와 같은가?
테스트가 정상적으로 작동하는지 확인하려면 다음 명령을 실행하세요:
forge test
출력
테스트 작성, 고급 테스트 및 기타 기능에 대해 자세히 알아보려면 Foundry 문서를 참조하세요.
컨트랙트 컴파일하기
이 명령으로 컨트랙트를 컴파일합니다:
forge build
컨트랙트 배포하기
Foundry를 사용하여 컨트랙트를 배포하려면, 컨트랙트를 배포할 계정의 RPC URL과 개인키를 제공해야 합니다. 클레이튼의 rpc 제공자 목록을 참고하여 rpc-url을 찾고, MetaMask를 사용하여 계정을 생성합니다.
1단계: 컨트랙트를 Klaytn Baobab 네트워크에 배포하려면, 아래 명령어를 실행합니다:
$ forge create --rpc-url <your_rpc_url> --private-key <your_private_key> src/Counter.sol:Counter
예시
forge create --rpc-url https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N --private-key hhdhdhdhprivatekeyhdhdhdhud src/Counter.sol:Counter
경고: 개인 키 인수를 MetaMask의 개인 키로 바꾸세요. 개인키가 노출되지 않도록 각별히 주의하세요.
출력
Step 2: Open Klaytnscope to check if the counter contract deployed successfully.
3단계: 검색 필드에 트랜잭션 해시를 복사하여 붙여넣고 Enter 키를 누릅니다. 최근에 배포된 컨트랙트가 표시됩니다.
컨트랙트와 상호작용하기
스마트 컨트랙트를 성공적으로 배포했다면, 이제 바로 함수를 호출하고 실행하고 싶을 것입니다. Cast를 사용하여 배포된 컨트랙트와 클레이튼 Baobab 네트워크에서 상호작용해 보겠습니다. 이번 장에서는 read-only
함수를 실행하기 위한 cast call과 write
함수를 실행하기 위한 cast send를 사용하는 방법을 배워보겠습니다.
A. Cast 호출: 컨트랙트에 저장된 번호를 가져오기 위해 number
함수를 호출하게 됩니다. 아래 명령어를 실행하여 실제로 작동하는지 확인해보세요.
cast call YOUR_CONTRACT_ADDRESS "number()" --rpc-url RPC-API-ENDPOINT-HERE
예시
cast call 0xe4d576c447733da7ca9197e88d34a74c3c865cff "number()" --rpc-url https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N
출력
이 데이터는 16진수 형식으로 가져와야 합니다:
0x0000000000000000000000000000000000000000000000000000000000000000
그러나 원하는 결과를 얻으려면 캐스팅을 사용하여 위의 결과를 변환합니다. 이 경우 데이터가 숫자이므로 기본 10으로 변환하여 결과 0을 얻을 수 있습니다:
cast --to-base 0x0000000000000000000000000000000000000000000000000000000000000000 10
출력
B. cast send: 카운터 컨트랙트에서 setNumber
함수를 실행하는 것과 같은 트랜잭션에 서명하고 게시하려면 아래 명령을 실행합니다:
cast send --rpc-url=<RPC-URL> <CONTRACT-ADDRESS> “setNumber(uint256)” arg --private-key=<PRIVATE-KEY>
예시
cast send --rpc-url=https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N 0xe4d576c447733da7ca9197e88d34a74c3c865cff "setNumber(uint256)" 10 --private-key=<private key>
출력
크로스체크 번호
cast call 0xe4d576c447733da7ca9197e88d34a74c3c865cff "number()" --rpc-url https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N
출력
이 데이터는 16진수 형식으로 가져와야 합니다:
0x000000000000000000000000000000000000000000000000000000000000000a
그러나 원하는 결과를 얻으려면 캐스팅을 사용하여 위의 결과를 변환합니다. 이 경우 데이터가 숫자이므로 기본 10으로 변환하여 결과 10을 얻을 수 있습니다:
cast --to-base 0x000000000000000000000000000000000000000000000000000000000000000a 10
출력