초보자를 위한 Hello World 스마트 컨트랙트
블록체인 개발이 처음이라 어디서부터 시작해야 할지 모르거나, 스마트 컨트랙트를 배포하고 상호작용하는 방법을 이해하고 싶다면 이 가이드가 도움이 될 것입니다. 가상 지갑인 메타마스크 (새 탭에서 열림), Solidity (새 탭에서 열림), Hardhat (새 탭에서 열림), 그리고 Alchemy (새 탭에서 열림)를 사용하여 Sepolia 테스트 네트워크에 간단한 스마트 컨트랙트를 생성하고 배포하는 과정을 살펴보겠습니다(이 용어들이 아직 무슨 뜻인지 몰라도 걱정하지 마세요. 차차 설명해 드릴 것입니다).
컨트랙트가 배포되면 이를 위한 사용자 인터페이스를 구축할 수 있습니다.
진행 중 궁금한 점이 있다면 언제든지 Alchemy 디스코드 (새 탭에서 열림)에 문의해 주세요!
1단계: 이더리움 네트워크에 연결하기
이더리움 체인에 요청을 보내는 방법은 여러 가지가 있습니다. 여기서는 간단하게 진행하기 위해 자체 노드를 실행하지 않고도 이더리움 체인과 통신할 수 있게 해주는 블록체인 개발자 플랫폼이자 API인 Alchemy의 무료 계정을 사용하겠습니다. 이 플랫폼에는 모니터링 및 분석을 위한 개발자 도구도 포함되어 있으며, 이 튜토리얼에서는 스마트 컨트랙트 배포 과정에서 내부적으로 어떤 일이 일어나는지 이해하기 위해 이 도구를 활용할 것입니다. 아직 Alchemy 계정이 없다면 여기에서 무료로 가입할 수 있습니다 (새 탭에서 열림).
2단계: 앱(및 API 키) 생성하기
Alchemy 계정을 생성한 후에는 앱을 생성하여 API 키를 발급받을 수 있습니다. 이를 통해 Sepolia 테스트 네트워크에 요청을 보낼 수 있습니다. 테스트넷에 익숙하지 않다면 이 페이지를 확인해 보세요.
- Alchemy 대시보드의 내비게이션 바에서 "Select an app"을 선택하고 "Create new app"을 클릭하여 "Create new app" 페이지로 이동합니다.
- 앱 이름을 "Hello World"로 지정하고, 간단한 설명을 추가한 뒤 사용 사례(예: "Infra & Tooling")를 선택합니다. 다음으로 "Ethereum"을 검색하고 네트워크를 선택합니다.
- "Next"를 클릭하여 진행한 다음 "Create app"을 클릭하면 완료됩니다! 내비게이션 바의 드롭다운 메뉴에 앱이 표시되며, 복사할 수 있는 API 키가 제공됩니다.
3단계: 이더리움 계정(주소) 생성하기
트랜잭션을 보내고 받으려면 이더리움 계정이 필요합니다. 이 튜토리얼에서는 이더리움 계정 주소를 관리하는 데 사용되는 브라우저 내 가상 지갑인 메타마스크를 사용하겠습니다. 트랜잭션에 대해 더 알아보세요.
여기 (새 탭에서 열림)에서 메타마스크를 다운로드하고 이더리움 계정을 무료로 생성할 수 있습니다. 계정을 생성할 때, 또는 이미 계정이 있는 경우 네트워크 드롭다운 메뉴를 사용하여 "Sepolia" 테스트 네트워크로 전환해야 합니다(실제 돈을 다루지 않기 위함입니다).
Sepolia가 목록에 보이지 않는다면, 오른쪽 상단의 메뉴를 열고 "Networks"를 선택한 다음 네트워크 목록 하단에서 "Show test networks"를 켜세요(테스트넷 보기에 대한 메타마스크의 가이드 (새 탭에서 열림) 참조). 그런 다음 네트워크 선택 메뉴에서 "Sepolia"를 선택합니다.
4단계: 퍼싯에서 이더 추가하기
테스트 네트워크에 스마트 컨트랙트를 배포하려면 가짜 ETH가 필요합니다. Sepolia ETH를 얻으려면 Sepolia 네트워크 세부 정보로 이동하여 다양한 퍼싯 목록을 확인할 수 있습니다. 하나가 작동하지 않으면 다른 것을 시도해 보세요. 퍼싯이 고갈되는 경우가 종종 있습니다. 일부 퍼싯에는 자격 요건이 있습니다. 예를 들어, Alchemy의 Sepolia 퍼싯은 수신 주소가 이더리움 메인넷에 최소 0.001 ETH를 보유하고 있어야 합니다. 네트워크 트래픽으로 인해 가짜 ETH를 받는 데 시간이 걸릴 수 있습니다. 곧 메타마스크 계정에서 ETH를 확인할 수 있을 것입니다!
5단계: 잔액 확인하기
잔액이 제대로 들어왔는지 다시 확인하기 위해 Alchemy의 컴포저 도구 (새 탭에서 열림)를 사용하여 eth_getBalance 요청을 보내보겠습니다. 이 요청은 지갑에 있는 ETH의 양을 반환합니다. 메타마스크 계정 주소를 입력하고 "Send Request"를 클릭하면 다음과 같은 응답을 볼 수 있습니다.
{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" }
참고: 이 결과는 ETH가 아니라 Wei 단위입니다. Wei는 이더의 가장 작은 단위로 사용됩니다. Wei에서 ETH로의 변환은 1 eth = 1018 Wei입니다. 따라서 0x2B5E3AF16B1880000을 십진수로 변환하면 5*10¹⁸이 되며, 이는 5 ETH와 같습니다.
휴! 가짜 돈이 모두 무사히 들어왔네요 .
6단계: 프로젝트 초기화하기
먼저 프로젝트를 위한 폴더를 만들어야 합니다. 명령줄로 이동하여 다음을 입력하세요.
mkdir hello-world
cd hello-world
이제 프로젝트 폴더 안에 있으므로 npm init을 사용하여 프로젝트를 초기화하겠습니다. 아직 npm이 설치되어 있지 않다면 Node.js 설치 지침 (새 탭에서 열림)을 따르세요(이 튜토리얼에서는 Node.js와 npm이 필요합니다).
npm init
설치 질문에 어떻게 대답하든 크게 상관없지만, 참고를 위해 우리가 작성한 방식은 다음과 같습니다.
package name: (hello-world)
version: (1.0.0)
description: hello world smart contract
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/.../.../.../hello-world/package.json:
{
"name": "hello-world",
"version": "1.0.0",
"description": "hello world smart contract",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
package.json을 승인합니다. 다음에 설치할 Hardhat 3는 ES 모듈 프로젝트만 지원하므로 프로젝트를 다음과 같이 표시하세요.
npm pkg set type=module
이제 준비가 완료되었습니다!
7단계: Hardhat (새 탭에서 열림) 다운로드하기
Hardhat은 이더리움 소프트웨어를 컴파일, 배포, 테스트 및 디버깅하기 위한 개발 환경입니다. 개발자가 라이브 체인에 배포하기 전에 로컬에서 스마트 컨트랙트와 탈중앙화 애플리케이션(dapp)을 구축할 때 도움을 줍니다.
Hardhat 3는 Node.js v22.13.0 이상이 필요합니다. hello-world 프로젝트 내에서 다음을 실행하세요.
npm install --save-dev hardhat
설치 지침 (새 탭에서 열림)에 대한 자세한 내용은 이 페이지를 확인하세요.
8단계: Hardhat 프로젝트 생성하기
npx hardhat --init을 실행하면 완전한 샘플 프로젝트가 생성되지만, 이 튜토리얼에서는 모든 요소를 확인할 수 있도록 수동으로 설정하겠습니다. 프로젝트 폴더의 루트에 다음 내용으로 hardhat.config.js라는 파일을 만드세요.
import { defineConfig } from "hardhat/config"
export default defineConfig({
solidity: "0.8.34",
})
이곳은 프로젝트의 모든 설정을 지정할 곳입니다(13단계에서 진행). 지금은 Hardhat에 사용할 Solidity 컴파일러 버전을 알려주는 역할만 합니다.
9단계: 프로젝트 폴더 추가하기
프로젝트를 체계적으로 관리하기 위해 두 개의 새 폴더를 만들겠습니다. 명령줄에서 프로젝트의 루트 디렉터리로 이동하여 다음을 입력하세요.
mkdir contracts
mkdir scripts
contracts/는 hello world 스마트 컨트랙트 코드 파일을 보관할 곳입니다.scripts/는 컨트랙트를 배포하고 상호작용하기 위한 스크립트를 보관할 곳입니다.
10단계: 컨트랙트 작성하기
도대체 언제 코드를 작성하는 건지 궁금하셨을 텐데요. 드디어 10단계에 도착했습니다.
선호하는 편집기(우리는 VSCode (새 탭에서 열림)를 좋아합니다)에서 hello-world 프로젝트를 엽니다. 스마트 컨트랙트는 Solidity라는 언어로 작성되며, 이를 사용하여 HelloWorld.sol 스마트 컨트랙트를 작성할 것입니다.
- "contracts" 폴더로 이동하여 HelloWorld.sol이라는 새 파일을 만듭니다.
- 아래는 이 튜토리얼에서 사용할 이더리움 재단의 샘플 Hello World 스마트 컨트랙트입니다. 아래 내용을 복사하여 HelloWorld.sol 파일에 붙여넣고, 주석을 읽어 이 컨트랙트가 어떤 역할을 하는지 이해해 보세요.
// SPDX-License-Identifier: MIT
// 시맨틱 버저닝을 사용하여 Solidity의 버전을 지정합니다.
// 자세히 알아보기: https://docs.soliditylang.org/en/latest/layout-of-source-files.html#pragma
pragma solidity ^0.8.24;
// `HelloWorld`라는 이름의 컨트랙트를 정의합니다.
// 컨트랙트는 함수와 데이터(상태)의 모음입니다. 배포되면 컨트랙트는 이더리움 블록체인의 특정 주소에 상주합니다. 자세히 알아보기: https://docs.soliditylang.org/en/latest/structure-of-a-contract.html
contract HelloWorld {
// `string` 타입의 상태 변수 `message`를 선언합니다.
// 상태 변수는 그 값이 컨트랙트 스토리지에 영구적으로 저장되는 변수입니다. `public` 키워드는 컨트랙트 외부에서 변수에 접근할 수 있게 하며, 다른 컨트랙트나 클라이언트가 값에 접근하기 위해 호출할 수 있는 함수를 생성합니다.
string public message;
// 많은 클래스 기반 객체 지향 언어와 유사하게, 생성자는 컨트랙트 생성 시에만 실행되는 특수한 함수입니다.
// 생성자는 컨트랙트의 데이터를 초기화하는 데 사용됩니다. 자세히 알아보기: https://docs.soliditylang.org/en/latest/contracts.html#constructors
constructor(string memory initMessage) {
// 문자열 인수 `initMessage`를 받아 컨트랙트의 `message` 스토리지 변수에 값을 설정합니다).
message = initMessage;
}
// 문자열 인수를 받아 `message` 스토리지 변수를 업데이트하는 public 함수입니다.
function update(string memory newMessage) public {
message = newMessage;
}
}
이것은 생성 시 메시지를 저장하고 update 함수를 호출하여 업데이트할 수 있는 매우 간단한 스마트 컨트랙트입니다.
11단계: 프로젝트에 메타마스크 및 Alchemy 연결하기
메타마스크 지갑, Alchemy 계정을 생성하고 스마트 컨트랙트를 작성했으니, 이제 이 세 가지를 연결할 차례입니다.
가상 지갑에서 전송되는 모든 트랜잭션에는 고유한 개인 키를 사용한 서명이 필요합니다. 프로그램에 이 권한을 제공하기 위해 환경 파일에 개인 키(및 Alchemy API 키)를 안전하게 저장할 수 있습니다.
트랜잭션 전송에 대해 자세히 알아보려면 트랜잭션 문서를 확인하세요.
프로젝트의 루트 디렉터리에 .env 파일을 만들고 메타마스크 개인 키와 HTTP Alchemy API URL을 추가합니다.
- 개인 키를 내보내려면 이 지침 (새 탭에서 열림)을 따르세요.
- HTTP Alchemy API URL을 얻으려면 아래를 참조하세요.
Alchemy API URL 복사
.env 파일은 다음과 같아야 합니다.
API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY="your-metamask-private-key"
이들을 코드에 실제로 연결하기 위해 13단계에서 hardhat.config.js 파일의 이 변수들을 참조할 것입니다. Node.js는 자체적으로 .env 파일을 읽을 수 있으므로 추가 패키지를 설치할 필요가 없습니다.
.env 파일을 커밋하지 마세요! .env 파일을 다른 사람과 공유하거나 노출하면 비밀 정보가 유출될 수 있으므로 절대 공유하지 마세요. 버전 관리를 사용하는 경우 .env를 gitignore 파일에 추가하세요.12단계: Ethers.js 설치하기
Ethers.js는 표준 JSON-RPC 메서드를 더 사용자 친화적인 메서드로 래핑하여 이더리움과 상호작용하고 요청을 보내기 쉽게 만들어주는 라이브러리입니다.
Hardhat을 사용하면 추가 도구 및 확장된 기능을 위한 플러그인 (새 탭에서 열림)을 매우 쉽게 통합할 수 있습니다. 컨트랙트 배포를 위해 Ethers 플러그인 (새 탭에서 열림)을 활용할 것입니다(Ethers.js (새 탭에서 열림)에는 매우 깔끔한 컨트랙트 배포 메서드가 있습니다).
프로젝트 디렉터리에서 다음을 입력하세요.
npm install --save-dev @nomicfoundation/hardhat-ethers ethers
다음 단계에서 hardhat.config.js에 플러그인을 추가할 것입니다.
13단계: hardhat.config.js 업데이트하기
지금까지 여러 종속성과 플러그인을 추가했으므로, 이제 프로젝트가 이 모든 것을 알 수 있도록 hardhat.config.js를 업데이트해야 합니다.
hardhat.config.js를 다음과 같이 업데이트하세요.
import { existsSync } from "node:fs"
import hardhatEthers from "@nomicfoundation/hardhat-ethers"
import { configVariable, defineConfig } from "hardhat/config"
// .env 파일이 존재하는 경우, 해당 파일에서 API_URL과 PRIVATE_KEY를 process.env로 로드합니다.
if (existsSync(".env")) process.loadEnvFile()
export default defineConfig({
plugins: [hardhatEthers],
solidity: "0.8.34",
networks: {
sepolia: {
type: "http",
url: configVariable("API_URL"),
accounts: [configVariable("PRIVATE_KEY")],
},
},
})
configVariable은 Hardhat이 필요할 때만 환경 변수에서 각 값을 읽도록 지시하므로, 값이 설정되기 전에도 compile과 같은 명령이 작동합니다. 개인 키를 일반 텍스트 파일에 보관하고 싶지 않다면, Hardhat은 암호화된 키스토어에서 구성 변수 (새 탭에서 열림)를 읽을 수도 있습니다.
14단계: 컨트랙트 컴파일하기
지금까지 모든 것이 제대로 작동하는지 확인하기 위해 컨트랙트를 컴파일해 보겠습니다. compile 작업은 내장된 Hardhat 작업 중 하나입니다.
명령줄에서 다음을 실행하세요.
npx hardhat compile
처음 컴파일할 때 Hardhat은 Solidity 컴파일러를 다운로드합니다. 그런 다음 Compiled 1 Solidity file with solc 0.8.34와 같은 메시지가 표시되어야 합니다. 그렇지 않다면 언제든지 Alchemy 디스코드 (새 탭에서 열림)에 메시지를 남겨주세요.
15단계: 배포 스크립트 작성하기
이제 컨트랙트가 작성되었고 구성 파일도 준비되었으니, 컨트랙트 배포 스크립트를 작성할 차례입니다.
scripts/ 폴더로 이동하여 deploy.js라는 새 파일을 만들고 다음 내용을 추가하세요.
import { network } from "hardhat"
const { ethers } = await network.create()
const HelloWorld = await ethers.getContractFactory("HelloWorld")
// 배포를 시작하고, 컨트랙트 객체로 이행되는 프로미스를 반환합니다.
const hello_world = await HelloWorld.deploy("Hello World!")
await hello_world.waitForDeployment()
console.log("Contract deployed to address:", await hello_world.getAddress())
이 코드의 각 줄이 어떤 역할을 하는지 살펴보겠습니다.
const { ethers } = await network.create()
Hardhat 3에서 스크립트는 네트워크에 대한 연결을 명시적으로 엽니다. network.create()는 스크립트를 실행할 때 --network 옵션으로 선택한 네트워크에 연결하며, hardhat-ethers 플러그인은 해당 연결에 ethers 객체를 추가합니다.
const HelloWorld = await ethers.getContractFactory("HelloWorld")
ethers.js의 ContractFactory는 새로운 스마트 컨트랙트를 배포하는 데 사용되는 추상화이므로, 여기서 HelloWorld는 hello world 컨트랙트의 인스턴스를 위한 팩토리입니다. hardhat-ethers 플러그인을 사용할 때 ContractFactory 및 Contract 인스턴스는 기본적으로 첫 번째 서명자에 연결됩니다.
const hello_world = await HelloWorld.deploy("Hello World!")
ContractFactory에서 deploy()를 호출하면 배포가 시작되고 Contract로 확인되는 Promise를 반환합니다. 이것은 스마트 컨트랙트의 각 함수에 대한 메서드를 가진 객체입니다. deploy()에 전달하는 인수는 컨트랙트의 생성자로 전달되며, 여기서는 초기 메시지입니다.
waitForDeployment()는 배포 트랜잭션이 블록에 포함될 때까지 기다리며, getAddress()는 새 컨트랙트의 주소를 반환합니다. 자세한 내용은 ethers.js 컨트랙트 문서 (새 탭에서 열림)를 참조하세요.
16단계: 컨트랙트 배포하기
드디어 스마트 컨트랙트를 배포할 준비가 되었습니다! 명령줄로 이동하여 다음을 실행하세요.
npx hardhat run scripts/deploy.js --network sepolia
그러면 다음과 같은 내용이 표시되어야 합니다.
Contract deployed to address: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570
Sepolia Etherscan (새 탭에서 열림)으로 이동하여 컨트랙트 주소를 검색하면 성공적으로 배포되었음을 확인할 수 있습니다. 트랜잭션은 다음과 같이 보일 것입니다.
From 주소는 메타마스크 계정 주소와 일치해야 하며 To 주소에는 "Contract Creation"이라고 표시되지만, 트랜잭션을 클릭하면 To 필드에서 컨트랙트 주소를 볼 수 있습니다.
축하합니다! 이더리움 체인에 스마트 컨트랙트를 배포했습니다 🎉
내부적으로 어떤 일이 일어나고 있는지 이해하려면 Alchemy 대시보드 (새 탭에서 열림)에서 "Hello World" 앱이 받은 요청을 살펴볼 수 있습니다.
그곳에서 .deploy() 함수를 호출했을 때 Hardhat/Ethers가 내부적으로 수행한 몇 가지 JSON-RPC 호출을 볼 수 있습니다. 여기서 주목해야 할 두 가지 중요한 호출은 실제로 Sepolia 체인에 컨트랙트를 기록하는 요청인 eth_sendRawTransaction과 해시가 주어졌을 때 트랜잭션에 대한 정보를 읽는 요청인 eth_getTransactionByHash입니다(트랜잭션을 보낼 때의 일반적인 패턴). 트랜잭션 전송에 대해 자세히 알아보려면 트랜잭션 문서를 확인하세요.
이 튜토리얼은 여기까지입니다. 다음으로 컨트랙트를 위한 사용자 인터페이스를 구축할 수 있습니다.





