Solidity 기본 (파트 1) — 변수, 함수 및 첫 번째 실제 컨트랙트
Source: Dev.to
Day 26 – Phase 3: 개발
60일 Web3 여정 – Solidity 기본
짧은 2일간의 휴식 후, 60일 Web3 여정을 다시 시작하고 Solidity에 첫 발을 내딛을 차례입니다.
지난 25일 동안 우리는 스마트 계약을 신비한 자판기처럼 다뤘습니다: 트랜잭션을 넣으면 체인에서 무언가가 일어나죠. 오늘은 그 뚜껑을 열고 자판기들이 쓰여 있는 언어, Solidity를 읽기 시작합니다.
오늘 다룰 내용
- 기본 빌딩 블록인 변수와 함수 이해하기.
- Sepolia에 작은 실제 계약 배포하기: Web3 Journey Logger.
목표: Solidity 전문가가 되는 것이 아니라, 체인 위에서 데이터를 저장하고 조작할 수 있는 기본 개념을 파악하는 것입니다.
1️⃣ Solidity 한눈에 보기
Solidity는 이더리움 및 기타 EVM‑호환 체인(Arbitrum, Optimism, Polygon 등)에서 실행되는 스마트 계약을 작성하기 위해 사용되는 고수준 계약‑지향 프로그래밍 언어입니다.
- Compiled → 체인 상 특정 주소에 존재하는 바이트코드.
- Executed → 트랜잭션을 처리하는 모든 노드에 의해 실행됩니다.
JavaScript, C++, TypeScript를 본 적이 있다면 Solidity는 친숙하게 느껴질 것입니다: 중괄호, 함수, 변수, if 조건문 등.
두 가지 중요한 차이점:
- UI만 다루는 것이 아니라 돈과 상태를 프로그래밍합니다.
- 모든 연산은 가스 비용이 들며, 배포한 코드는 대부분 영구적입니다.
2️⃣ 변수 – 계약의 메모리
스마트 계약을 자체적인 개인 데이터베이스를 가진 작은 온‑체인 애플리케이션이라고 생각하면 됩니다. 변수는 이 계약이 데이터를 저장하는 이름이 붙은 상자입니다.
Solidity에서는 타입과 이름을 모두 선언해야 합니다. 컴파일러가 정확히 무엇을 어디에 저장할지 알아야 하기 때문입니다.
변수의 세 가지 레벨
| 레벨 | 범위 | 지속성 | 일반적인 사용 |
|---|---|---|---|
| State variables | 블록체인 상 계약의 스토리지에 영구적으로 저장됩니다. | 함수 호출 및 트랜잭션 사이에 지속됩니다. | 소유자 주소, 토큰 잔액 매핑, 카운터 등 |
| Local variables | 함수 내부에서 선언됩니다. | 해당 함수가 실행되는 동안에만 존재하고, 종료되면 사라집니다. | uint256 sum = a + b; (함수 내부) |
| Global variables | EVM이 제공하는 내장 헬퍼. | 실행 중 읽기 전용입니다. | msg.sender, block.timestamp, block.number |
이 첫 단계에서는 state variables에 집중합니다. 이 변수들이 계약의 온‑체인 메모리를 구성하기 때문입니다.
핵심 데이터 타입 (거의 모든 계약에서 볼 수 있는 타입)
| 타입 | 설명 | 예시 |
|---|---|---|
bool | true 또는 false 를 저장합니다. | bool public completed; |
uint256 | 부호 없는 정수(0 및 양수). 금액, ID, 카운터, 타임스탬프 등에 일반적으로 사용됩니다. | uint256 public dayNumber; |
address | 이더리움 주소(사용자 또는 계약)를 저장합니다. | address public owner; |
string | 텍스트 데이터를 저장합니다. 가스 비용이 숫자보다 비싸므로 필요할 때만 사용하세요. | string public note; |
int,bytes,mapping,struct, 배열 등 더 많은 타입이 있지만, 시작하기엔 이 네 가지면 충분합니다.
3️⃣ 함수 – 문과 버튼
변수가 계약의 메모리라면, 함수는 사용자가 그 메모리를 읽거나 업데이트할 수 있는 문과 버튼입니다.
누군가 트랜잭션이나 UI(예: dApp)를 통해 함수를 호출할 때마다, EVM은 함수 로직을 단계별로 실행합니다.
기본 함수 구문
function setDay(uint256 _day) public {
dayNumber = _day;
}
setDay– 함수 이름.uint256 _day– 입력 파라미터.public– 가시성 지정자.- 본문(
{ … })은dayNumber상태 변수를 업데이트합니다.
가시성 수정자
| Modifier | 누가 호출할 수 있나요? |
|---|---|
public | 누구든지, 다른 계약을 포함합니다. 자동으로 계약의 외부 인터페이스의 일부가 됩니다. |
external | 계약 외부에서 호출하도록 설계되었습니다. 순수 외부 호출에 대해 약간 더 가스 효율적입니다. |
internal / private | 헬퍼 함수에 사용됩니다; 여기서는 다루지 않으며(나중에 등장합니다). |
setEntry(아래 예시에서) 은public으로 표시되어 있지만, 약간의 가스 절감을 위해external로 할 수 있습니다.
상태 상호작용 수정자
| Modifier | 동작 |
|---|---|
view | 상태 변수를 읽을 수 있지만 수정할 수는 없습니다. 오프체인에서 호출될 때(예: Etherscan) 가스 비용이 발생하지 않습니다. |
pure | 상태를 읽거나 수정할 수 없습니다. 입력값과 로컬 변수만 사용합니다. |
예시 함수
function getDay() public view returns (uint256) {
return dayNumber;
}
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
4️⃣ 프로젝트: Web3 여정 로거
Instead of another generic “Simple Storage” example, we’ll build a Web3 Journey Logger contract that ties directly into this learning challenge.
계약이 하는 일
- 이름 저장 (학습자 핸들).
- 현재 학습 일수 번호 저장.
- 그 날에 대한 짧은 메모 저장.
핵심 동작
| 동작 | 설명 |
|---|---|
| 소유자 | 배포될 때, 배포자를 기억합니다 (owner). |
| 업데이트 | dayNumber와 note를 최신 항목에 대해 업데이트할 수 있습니다. |
| 읽기 | 누구든지 저장된 값(name, dayNumber, note)을 읽을 수 있습니다. |
5️⃣ 전체 계약 코드
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Web3JourneyLogger {
// ── State variables ──
/// @notice Address of the person who deployed the contract
address public owner;
/// @notice Name or handle of the learner
string public name;
/// @notice Current day in the learning journey
uint256 public dayNumber;
/// @notice Short note for the current day
string public note;
// ── Constructor ──
/**
* @dev Sets the contract deployer as `owner` and initializes the learner's `name`.
* @param _name The learner's name or handle.
*/
constructor(string memory _name) {
owner = msg.sender;
name = _name;
}
// ── Core functions ──
/**
* @dev Updates the current day number and an optional note.
* Only the contract `owner` can call this function.
* @param _day New day number.
* @param _note Short note for the day.
*/
function setEntry(uint256 _day, string calldata _note) external {
require(msg.sender == owner, "Only owner can update");
dayNumber = _day;
note = _note;
}
/**
* @dev Returns the stored learner information.
* @return _name Learner's name.
* @return _day Current day number.
* @return _note Current note.
*/
function getEntry()
external
view
returns (string memory _name, uint256 _day, string memory _note)
{
return (name, dayNumber, note);
}
}
작동 방식
| 함수 | 가시성 | 상태 상호작용 | 누가 호출할 수 있나요? |
|---|---|---|---|
constructor | public (한 번 실행) | owner와 name을 쓰기 | 배포자 |
setEntry | external | 쓰기 dayNumber와 note (소유자만 가능) | 소유자만 |
getEntry | external view | 읽기 모든 public 변수 | 누구나 |
이 계약을 Sepolia(또는 EVM 호환 테스트넷) 에 배포하면, Web3 학습 여정을 기록하는 개인 온‑체인 저널을 갖게 됩니다.
6️⃣ 다음 단계
- Compile & Deploy 계약을 Remix, Hardhat, 또는 Foundry를 사용하여 컴파일하고 배포합니다.
- Interact
setEntry와 상호작용하여 새로운 날짜와 메모를 기록합니다. - Read
getEntry를 통해 또는 자동 생성된 getter(owner(),name(),dayNumber(),note())를 직접 사용하여 데이터를 읽습니다.
이것으로 Day 26이 끝났습니다! 이제 variables와 functions가 결합하여 실제로 사용할 수 있는 온‑체인 애플리케이션을 만드는 구체적인 예시를 갖게 되었습니다. 내일은 더 복잡한 데이터 구조(매핑, 구조체)를 깊이 파고들고, 계약을 더 안전하고 가스 효율적으로 만드는 방법을 탐구합니다. 코딩 즐겁게!
Web3 여정 로거 – 최소 Solidity 계약
아래는 일일 항목(날짜 번호와 짧은 메모)을 기록하는 간단한 Solidity 계약입니다. 이 예제는 다음을 보여줍니다:
- 상태 변수와 생성자
- 기본 접근 제어가 포함된 상태‑변경 함수
- 여러 값을 반환하는 view 함수
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Web3JourneyLogger {
address public owner;
string public name;
uint256 public dayNumber;
string public note;
// Constructor – runs once when the contract is deployed
constructor(string memory _name) {
owner = msg.sender;
name = _name;
}
// Update the current day and note (only the owner can call)
function setEntry(uint256 _dayNumber, string calldata _note) public {
require(msg.sender == owner, "Not owner");
dayNumber = _dayNumber;
note = _note;
}
// Helper to read all data in one call
function getEntry()
public
view
returns (
string memory _name,
uint256 _day,
string memory _note
)
{
return (name, dayNumber, note);
}
}
이 최소 계약은 상태 변수, 생성자, 간단한 접근 제어 검사를 포함한 상태‑변경 함수, 그리고 여러 값을 반환하는 view 함수를 보여줍니다.
Deploying to Sepolia with Remix & MetaMask
Prerequisites
- MetaMask (또는 다른 Web3 지갑)이 브라우저에 설치되어 있어야 합니다.
- 지갑이 Sepolia 테스트 네트워크에 연결되어 있어야 합니다.
- 배포 가스 비용을 충당할 수 있도록 Sepolia 파우셋에서 받은 테스트 ETH가 조금 필요합니다.
Step‑by‑step Guide
- Open Remix – Solidity용 브라우저 기반 IDE를 엽니다.
- Create a new file
- 파일 탐색기에서 + 버튼을 클릭하고 파일 이름을
Web3JourneyLogger.sol로 지정합니다.
- 파일 탐색기에서 + 버튼을 클릭하고 파일 이름을
- Paste the contract code (위의 스니펫) 를 파일에 붙여넣습니다.
- Compile the contract
- Solidity Compiler 탭을 엽니다.
- pragma와 일치하는 컴파일러 버전을 선택합니다(예: 0.8.20).
- Compile Web3JourneyLogger.sol 버튼을 클릭합니다.
- Deploy to Sepolia
- Deploy & Run Transactions 탭을 엽니다.
- Environment 를 Injected Provider – MetaMask 로 설정합니다.
- MetaMask가 Sepolia 네트워크에 있는지 확인합니다.
- Contract 드롭다운에서
Web3JourneyLogger가 선택되어 있는지 확인합니다. - Constructor Arguments 필드에 이름 문자열을 입력합니다(예:
"Ribhav"). - Deploy 버튼을 클릭하고 MetaMask에서 트랜잭션을 확인합니다.
- Verify deployment
- 트랜잭션이 채굴된 후 Remix에 Deployed Contracts 섹션이 표시되고, 여기서 배포된 계약 인스턴스를 확인할 수 있습니다.
- 트랜잭션 해시를 이용해 Sepolia Etherscan에서 트랜잭션을 조회할 수 있습니다.
- Interact with the contract
- Deployed Contracts 아래에 있는 배포된 인스턴스를 펼칩니다.
- 자동 생성된 getter(
owner,name,dayNumber,note)를 호출해 현재 값을 확인합니다. setEntry를 사용해 새로운 날짜 번호와 메모를 저장합니다(오직 소유자만 호출 가능).- 개별 getter 또는
getEntryview 함수로 데이터를 다시 조회합니다.
이 과정을 매일 반복하면, 계약은 여러분의 Web3 학습 여정을 기록하는 작은 온‑체인 일기가 됩니다.
왜 이것이 중요한가
모든 DeFi 프로토콜, NFT 마켓플레이스, 혹은 DAO는 결국 여기서 소개한 변수와 함수들의 보다 복잡한 조합입니다. 다음을 이해하는 것이 중요합니다:
- 상태가 어떻게 저장되는지
- 함수가 그 상태를 어떻게 노출하거나 보호하는지
- 계약이 네트워크에 어떻게 배포되는지
이는 안전한 스마트‑컨트랙트 개발 및 감시의 기반이 됩니다.
다음 단계에서는 배열, 매핑, 구조체, 접근 제어 패턴 및 Hardhat, Foundry와 같은 로컬 개발 도구로 범위를 확장할 예정이며, 모두 이 첫 번째 Solidity 기사에서 제시된 핵심 아이디어를 기반으로 합니다.
추가 읽을거리
- Solidity Official Docs – Introduction to Smart Contracts
- Solidity by Example – Simple Storage and Basics
- GeeksforGeeks – Solidity Basics of Contracts
- GeeksforGeeks – Solidity Variables
- GeeksforGeeks – Solidity Functions
- Dapp University – Solidity for Beginners
연결 유지
- 시리즈를 Medium, Twitter, Future에서 팔로우하세요
- Telegram에서 Web3ForHumans에 참여하세요 – 함께 Web3를 브레인스토밍해요!