도입
2025년 블록체인 생태계는 투기적 광풍의 시대를 지나 실질적인 기술 인프라로 자리 잡았습니다. Ethereum의 Dencun 업그레이드, Layer 2 롤업의 폭발적 성장, 그리고 RWA(Real World Assets) 토큰화가 주류 금융과 만나면서, Web3 개발자에 대한 수요는 사상 최고치를 기록하고 있습니다.
이 가이드에서는 블록체인의 핵심 원리부터 Solidity 스마트 컨트랙트 개발, 보안, DeFi/NFT 생태계, 그리고 Web3 개발자 커리어까지 체계적으로 다룹니다.
> **핵심 표현 정리**
>
> | 표현 | 의미 |
> |------|------|
> | **Smart Contract** | 블록체인 위에서 자동 실행되는 프로그램. 코드가 곧 계약 |
> | **Layer 2** | 메인넷(L1) 위에 구축된 확장 솔루션. 처리량 증가, 비용 감소 |
> | **DeFi** | 탈중앙화 금융. 중개자 없이 스마트 컨트랙트로 금융 서비스 제공 |
> | **Gas Optimization** | 스마트 컨트랙트 실행 비용(Gas)을 최소화하는 최적화 기법 |
1. 블록체인 기초 원리
1.1 블록체인이란?
블록체인은 분산 네트워크의 모든 참여자가 동일한 거래 기록(원장)을 공유하는 기술입니다. 각 블록은 이전 블록의 해시를 포함하여 체인을 형성합니다.
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Block 0 │───▶│ Block 1 │───▶│ Block 2 │
│ (Genesis)│ │ │ │ │
│ Hash: 0a │ │ Prev: 0a │ │ Prev: 7f │
│ Nonce: 42│ │ Hash: 7f │ │ Hash: b3 │
│ Txs: [] │ │ Txs: [..] │ │ Txs: [..]│
└──────────┘ └──────────┘ └──────────┘
1.2 합의 메커니즘 비교
| 항목 | PoW (Proof of Work) | PoS (Proof of Stake) | DPoS |
|------|---------------------|----------------------|------|
| 에너지 소비 | 매우 높음 | 낮음 | 낮음 |
| 분산성 | 높음 | 중간 | 낮음 |
| TPS | 7-15 | 30-100K+ | 1000+ |
| 대표 체인 | Bitcoin | Ethereum 2.0 | EOS, Tron |
| 참여 조건 | 해시파워 (GPU/ASIC) | 스테이킹 자산 | 투표 위임 |
| 파이널리티 | 확률적 (6블록) | 에포크 기반 확정 | 빠른 확정 |
1.3 해시 함수와 머클 트리
블록체인의 무결성은 암호학적 해시 함수에 의존합니다.
def calculate_hash(block_data):
"""블록 데이터의 SHA-256 해시 계산"""
data_string = str(block_data).encode()
return hashlib.sha256(data_string).hexdigest()
머클 트리 구현
def merkle_root(transactions):
if len(transactions) == 0:
return hashlib.sha256(b'').hexdigest()
if len(transactions) == 1:
return transactions[0]
new_level = []
for i in range(0, len(transactions), 2):
left = transactions[i]
right = transactions[i + 1] if i + 1 < len(transactions) else left
combined = hashlib.sha256((left + right).encode()).hexdigest()
new_level.append(combined)
return merkle_root(new_level)
1.4 트랜잭션 생명주기
사용자 → 트랜잭션 생성 → 서명(개인키) → 브로드캐스트
→ Mempool 진입 → 검증자/채굴자 선택 → 블록 포함
→ 합의 → 블록 확정 → 상태 업데이트
2. Ethereum과 EVM 깊이 이해하기
2.1 Ethereum 아키텍처
Ethereum은 **월드 컴퓨터**라는 비전으로 시작되었습니다. 비트코인이 거래 기록만 저장하는 반면, Ethereum은 **Turing-complete** 가상 머신(EVM)을 통해 임의의 로직을 실행할 수 있습니다.
┌─────────────────────────────────────────┐
│ Ethereum Network │
├─────────────────────────────────────────┤
│ ┌─────────┐ ┌──────────┐ ┌────────┐ │
│ │ EOA │ │ Contract │ │Contract│ │
│ │ Account │──│ Account │──│Account │ │
│ │ (사용자)│ │ (코드) │ │(코드) │ │
│ └─────────┘ └──────────┘ └────────┘ │
├─────────────────────────────────────────┤
│ EVM (실행 엔진) │
├─────────────────────────────────────────┤
│ State Trie (상태 저장) │
└─────────────────────────────────────────┘
2.2 EVM 동작 원리
EVM은 스택 기반 가상 머신으로, 256비트 워드 크기를 사용합니다.
EVM 메모리 모델:
┌─────────────┐
│ Stack │ ← 최대 1024 깊이, LIFO
│ (256-bit) │
├─────────────┤
│ Memory │ ← 바이트 배열, 휘발성
│ (확장 가능)│
├─────────────┤
│ Storage │ ← key-value, 영구 저장
│ (256→256) │
└─────────────┘
주요 Opcode 예시:
PUSH1 0x60 // 스택에 0x60 push
PUSH1 0x40 // 스택에 0x40 push
MSTORE // Memory[0x40] = 0x60
CALLVALUE // msg.value를 스택에
DUP1 // 스택 top 복제
ISZERO // 0이면 1, 아니면 0
2.3 Gas 시스템
모든 EVM 연산에는 Gas 비용이 부과됩니다.
| 연산 | Gas 비용 | 설명 |
|------|----------|------|
| ADD / SUB | 3 | 산술 연산 |
| MUL / DIV | 5 | 곱셈 / 나눗셈 |
| SLOAD | 2100 (cold) / 100 (warm) | Storage 읽기 |
| SSTORE | 20000 (new) / 5000 (update) | Storage 쓰기 |
| CALL | 2600 (cold) / 100 (warm) | 외부 호출 |
| CREATE | 32000 | 컨트랙트 생성 |
Gas 비용 계산 공식:
총 비용 = Gas Used * Gas Price (Gwei)
= Gas Used * (Base Fee + Priority Fee)
예시: 21000 Gas * 30 Gwei = 630,000 Gwei = 0.00063 ETH
3. Solidity 스마트 컨트랙트 개발
3.1 기본 문법
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title SimpleStorage
* @dev 기본적인 상태 저장 컨트랙트
*/
contract SimpleStorage {
// 상태 변수
uint256 private storedValue;
address public owner;
mapping(address => uint256) public balances;
// 이벤트
event ValueChanged(address indexed setter, uint256 newValue);
// 수정자
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
constructor(uint256 _initialValue) {
owner = msg.sender;
storedValue = _initialValue;
}
function setValue(uint256 _value) external onlyOwner {
storedValue = _value;
emit ValueChanged(msg.sender, _value);
}
function getValue() external view returns (uint256) {
return storedValue;
}
}
3.2 ERC-20 토큰 구현
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract MyToken is ERC20, Ownable {
uint256 public constant MAX_SUPPLY = 1_000_000 * 10**18;
constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {
_mint(msg.sender, MAX_SUPPLY);
}
function burn(uint256 amount) external {
_burn(msg.sender, amount);
}
}
3.3 ERC-721 NFT 구현
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract MyNFT is ERC721, ERC721URIStorage, Ownable {
uint256 private _nextTokenId;
uint256 public mintPrice = 0.05 ether;
uint256 public maxSupply = 10000;
constructor() ERC721("MyNFT", "MNFT") Ownable(msg.sender) {}
function mint(string memory uri) external payable {
require(msg.value >= mintPrice, "Insufficient payment");
require(_nextTokenId < maxSupply, "Max supply reached");
uint256 tokenId = _nextTokenId++;
_safeMint(msg.sender, tokenId);
_setTokenURI(tokenId, uri);
}
function tokenURI(uint256 tokenId)
public view override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public view override(ERC721, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function withdraw() external onlyOwner {
payable(owner()).transfer(address(this).balance);
}
}
3.4 고급 패턴: Proxy (업그레이드 가능 컨트랙트)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Implementation V1
contract BoxV1 {
uint256 private value;
function store(uint256 newValue) public {
value = newValue;
}
function retrieve() public view returns (uint256) {
return value;
}
}
// Implementation V2 (업그레이드 후)
contract BoxV2 {
uint256 private value;
function store(uint256 newValue) public {
value = newValue;
}
function retrieve() public view returns (uint256) {
return value;
}
function increment() public {
value += 1;
}
}
4. 개발 도구: Hardhat vs Foundry
4.1 Hardhat 설정 및 사용
프로젝트 초기화
mkdir my-project && cd my-project
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
Hardhat 프로젝트 생성
npx hardhat init
// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: {
version: "0.8.20",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
networks: {
sepolia: {
url: process.env.SEPOLIA_RPC_URL || "",
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
},
hardhat: {
forking: {
url: process.env.MAINNET_RPC_URL || "",
blockNumber: 18_000_000,
},
},
},
};
Hardhat 테스트 예시:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("SimpleStorage", function () {
let storage;
let owner;
let addr1;
beforeEach(async function () {
[owner, addr1] = await ethers.getSigners();
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
storage = await SimpleStorage.deploy(42);
});
it("Should store the initial value", async function () {
expect(await storage.getValue()).to.equal(42);
});
it("Should allow owner to set value", async function () {
await storage.setValue(100);
expect(await storage.getValue()).to.equal(100);
});
it("Should reject non-owner setValue", async function () {
await expect(
storage.connect(addr1).setValue(100)
).to.be.revertedWith("Not the owner");
});
});
4.2 Foundry 설정 및 사용
Foundry 설치
curl -L https://foundry.paradigm.xyz | bash
foundryup
프로젝트 생성
forge init my-foundry-project
cd my-foundry-project
foundry.toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 200
solc_version = "0.8.20"
[profile.default.fuzz]
runs = 1000
max_test_rejects = 65536
[rpc_endpoints]
mainnet = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
sepolia = "https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY"
Foundry 테스트 (Solidity로 작성):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract SimpleStorageTest is Test {
SimpleStorage public store;
address public owner = address(this);
address public user = address(0x1);
function setUp() public {
store = new SimpleStorage(42);
}
function testInitialValue() public view {
assertEq(store.getValue(), 42);
}
function testSetValue() public {
store.setValue(100);
assertEq(store.getValue(), 100);
}
function testFailNonOwnerSetValue() public {
vm.prank(user);
store.setValue(100); // 이 호출은 revert 됨
}
// Fuzz 테스트
function testFuzzSetValue(uint256 value) public {
store.setValue(value);
assertEq(store.getValue(), value);
}
}
4.3 Hardhat vs Foundry 비교
| 기능 | Hardhat | Foundry |
|------|---------|---------|
| 언어 | JavaScript/TypeScript | Solidity |
| 테스트 속도 | 보통 | 매우 빠름 (10x+) |
| Fuzz 테스트 | 플러그인 필요 | 내장 |
| 디버깅 | console.log | forge debug (step) |
| 포크 테스트 | 지원 | 지원 (더 빠름) |
| 플러그인 생태계 | 풍부 | 성장 중 |
| Gas 리포트 | hardhat-gas-reporter | forge test --gas-report |
| 학습 곡선 | JS 개발자 친화적 | Solidity 집중 |
5. 스마트 컨트랙트 보안
5.1 Reentrancy 공격
가장 유명한 스마트 컨트랙트 취약점으로, 2016년 The DAO 해킹(6000만 달러 피해)의 원인입니다.
// 취약한 코드
contract VulnerableVault {
mapping(address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
// 위험: 외부 호출 후 상태 업데이트
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "No balance");
// 외부 호출 (공격 벡터)
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
// 상태 업데이트가 외부 호출 뒤에!
balances[msg.sender] = 0;
}
}
// 공격자 컨트랙트
contract Attacker {
VulnerableVault public vault;
constructor(address _vault) {
vault = VulnerableVault(_vault);
}
function attack() external payable {
vault.deposit{value: msg.value}();
vault.withdraw();
}
// withdraw()의 call이 여기로 돌아옴 -> 다시 withdraw() 호출
receive() external payable {
if (address(vault).balance > 0) {
vault.withdraw();
}
}
}
**해결 방법: Checks-Effects-Interactions 패턴**
contract SecureVault {
mapping(address => uint256) public balances;
bool private locked;
modifier noReentrant() {
require(!locked, "Reentrant call");
locked = true;
_;
locked = false;
}
function withdraw() external noReentrant {
uint256 amount = balances[msg.sender];
require(amount > 0, "No balance");
// Effects (상태 업데이트 먼저)
balances[msg.sender] = 0;
// Interactions (외부 호출 나중에)
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
5.2 Integer Overflow/Underflow
Solidity 0.8.0 이전에는 자동 오버플로우 체크가 없었습니다.
// Solidity 0.7.x 이전: 위험!
// uint8 max = 255; max + 1 = 0 (overflow)
// uint8 min = 0; min - 1 = 255 (underflow)
// Solidity 0.8.0+: 자동으로 revert
// 성능이 필요한 경우 unchecked 블록 사용
function unsafeIncrement(uint256 x) pure returns (uint256) {
unchecked {
return x + 1; // overflow 체크 안 함 (Gas 절약)
}
}
5.3 보안 체크리스트
보안 감사 체크리스트:
[1] Reentrancy
- CEI 패턴 적용 확인
- ReentrancyGuard 사용 여부
[2] 접근 제어
- onlyOwner / Role 기반 접근 제어
- 초기화 함수 보호
[3] 산술 연산
- Solidity 0.8+ 사용 (자동 체크)
- unchecked 블록 검토
[4] 외부 호출
- call 반환값 체크
- 가스 제한 설정
[5] 프론트러닝
- commit-reveal 패턴
- Flashbots 사용 고려
[6] 오라클 조작
- TWAP (시간 가중 평균 가격) 사용
- 다중 오라클 소스
[7] 플래시론 공격
- 단일 트랜잭션 조작 방어
- 가격 검증 로직
[8] 스토리지 충돌 (Proxy)
- EIP-1967 스토리지 슬롯
- 업그레이드 테스트
5.4 주요 해킹 사례
| 사건 | 연도 | 피해액 | 취약점 |
|------|------|--------|--------|
| The DAO | 2016 | 6000만 달러 | Reentrancy |
| Ronin Bridge | 2022 | 6.25억 달러 | 개인키 탈취 |
| Wormhole | 2022 | 3.2억 달러 | 서명 검증 우회 |
| Euler Finance | 2023 | 1.97억 달러 | Donate 함수 취약점 |
| Mango Markets | 2022 | 1.14억 달러 | 오라클 조작 |
6. Layer 2 솔루션 비교
6.1 Layer 2란?
Layer 2(L2)는 Ethereum 메인넷(L1)의 보안을 상속하면서 처리량을 확장하는 솔루션입니다.
┌─────────────────────────────────────────┐
│ 사용자 (Dapp) │
├────────────┬────────────┬───────────────┤
│ Optimistic │ ZK Rollup │ Validium │
│ Rollup │ │ │
│ (Arbitrum, │ (zkSync, │ (StarkEx, │
│ Optimism, │ Scroll, │ zkPorter) │
│ Base) │ Linea) │ │
├────────────┴────────────┴───────────────┤
│ Ethereum L1 (보안 레이어) │
└─────────────────────────────────────────┘
6.2 Optimistic vs ZK Rollup
| 특성 | Optimistic Rollup | ZK Rollup |
|------|-------------------|-----------|
| 검증 방식 | 사기 증명 (Fraud Proof) | 유효성 증명 (Validity Proof) |
| 인출 시간 | 7일 (챌린지 기간) | 수분~수시간 |
| EVM 호환 | 높음 | 성장 중 (zkEVM) |
| 가스 비용 | L1 대비 10-50x 저렴 | L1 대비 50-100x 저렴 |
| 대표 체인 | Arbitrum, Optimism, Base | zkSync Era, Scroll, Linea |
| 성숙도 | 높음 | 빠르게 성장 |
6.3 주요 L2 체인 상세 비교
TVL (Total Value Locked) 순위 (2025년 기준):
1. Arbitrum One - TVL: 약 180억 달러
- Nitro 기술 스택
- EVM 완전 호환
- Stylus (Rust/C++ 지원)
2. Base - TVL: 약 120억 달러
- Coinbase 지원
- OP Stack 기반
- 소비자 앱 강세
3. Optimism - TVL: 약 80억 달러
- OP Stack (Superchain 비전)
- Bedrock 업그레이드
- RetroPGF (공공재 펀딩)
4. zkSync Era - TVL: 약 40억 달러
- zkEVM (LLVM 기반)
- 네이티브 Account Abstraction
- Hyperchain 확장
5. Scroll - TVL: 약 20억 달러
- Type-2 zkEVM
- 이더리움 바이트코드 호환
6.4 L2에서의 개발
// Arbitrum에 배포하기 (Hardhat)
// hardhat.config.js에 네트워크 추가
module.exports = {
networks: {
arbitrum: {
url: "https://arb1.arbitrum.io/rpc",
accounts: [process.env.PRIVATE_KEY],
chainId: 42161,
},
base: {
url: "https://mainnet.base.org",
accounts: [process.env.PRIVATE_KEY],
chainId: 8453,
},
optimism: {
url: "https://mainnet.optimism.io",
accounts: [process.env.PRIVATE_KEY],
chainId: 10,
},
},
};
// 배포 스크립트
async function main() {
const Contract = await ethers.getContractFactory("MyContract");
const contract = await Contract.deploy();
await contract.waitForDeployment();
console.log("Deployed to:", await contract.getAddress());
}
7. DeFi 프로토콜 이해
7.1 DeFi 핵심 프리미티브
DeFi 스택:
┌─────────────────────────────────────┐
│ Aggregator / Frontend │
│ (1inch, DefiLlama, Zapper) │
├─────────────────────────────────────┤
│ Application Layer │
│ (Aave, Uniswap, MakerDAO) │
├─────────────────────────────────────┤
│ Protocol Layer │
│ (AMM, Lending, Derivatives) │
├─────────────────────────────────────┤
│ Asset Layer │
│ (ERC-20, ERC-721, Wrapped) │
├─────────────────────────────────────┤
│ Settlement Layer │
│ (Ethereum, L2 Rollups) │
└─────────────────────────────────────┘
7.2 AMM (Automated Market Maker)
Uniswap V2의 핵심 공식: `x * y = k`
// 간단한 AMM 구현
contract SimpleAMM {
uint256 public reserveA;
uint256 public reserveB;
uint256 public totalLiquidity;
mapping(address => uint256) public liquidity;
// 유동성 공급
function addLiquidity(uint256 amountA, uint256 amountB) external {
// 실제로는 토큰 전송 로직 포함
reserveA += amountA;
reserveB += amountB;
uint256 liq;
if (totalLiquidity == 0) {
liq = sqrt(amountA * amountB);
} else {
liq = min(
(amountA * totalLiquidity) / reserveA,
(amountB * totalLiquidity) / reserveB
);
}
liquidity[msg.sender] += liq;
totalLiquidity += liq;
}
// 스왑: A를 넣고 B를 받기
function swapAForB(uint256 amountAIn) external returns (uint256) {
// x * y = k 기반 계산
uint256 amountBOut = (amountAIn * reserveB) / (reserveA + amountAIn);
// 0.3% 수수료 적용
amountBOut = (amountBOut * 997) / 1000;
reserveA += amountAIn;
reserveB -= amountBOut;
return amountBOut;
}
function sqrt(uint256 x) internal pure returns (uint256) {
uint256 z = (x + 1) / 2;
uint256 y = x;
while (z < y) {
y = z;
z = (x / z + z) / 2;
}
return y;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
7.3 Lending Protocol 개념
Lending Protocol (예: Aave):
1. 예치 (Supply)
사용자 → 자산 예치 → aToken 수령 (이자 자동 누적)
2. 대출 (Borrow)
담보 예치 → 건전성 비율(HF) 확인 → 자산 대출
HF = 담보가치 * LTV / 대출가치
3. 청산 (Liquidation)
HF가 1 미만 → 청산자가 부채 상환 → 담보 할인 매입
담보비율 예시:
- ETH: LTV 80%, 청산 임계값 82.5%
- USDC: LTV 77%, 청산 임계값 80%
8. Gas Optimization 기법
8.1 Storage 최적화
// Bad: 각 변수가 별도 슬롯 사용
contract BadPacking {
uint256 a; // slot 0 (32 bytes)
uint8 b; // slot 1 (1 byte, 나머지 31 낭비)
uint256 c; // slot 2
uint8 d; // slot 3
}
// 총 4 슬롯 사용
// Good: 변수 패킹으로 슬롯 절약
contract GoodPacking {
uint256 a; // slot 0
uint256 c; // slot 1
uint8 b; // slot 2 (b와 d가 같은 슬롯)
uint8 d; // slot 2
}
// 총 3 슬롯 사용 (SSTORE 20000 gas 절약)
8.2 루프 최적화
// Bad
function sumBad(uint256[] memory arr) public pure returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
// Good: length 캐싱 + unchecked increment
function sumGood(uint256[] memory arr) public pure returns (uint256) {
uint256 total = 0;
uint256 len = arr.length;
for (uint256 i = 0; i < len; ) {
total += arr[i];
unchecked { ++i; }
}
return total;
}
8.3 기타 최적화 기법
// 1. calldata vs memory (읽기 전용 매개변수)
function process(uint256[] calldata data) external pure { /* ... */ }
// calldata: 수정 불가, Gas 저렴
// memory: 수정 가능, Gas 비쌈
// 2. Custom Errors (Solidity 0.8.4+)
error Unauthorized(address caller);
error InsufficientBalance(uint256 available, uint256 required);
function withdraw(uint256 amount) external {
if (msg.sender != owner) revert Unauthorized(msg.sender);
if (balances[msg.sender] < amount)
revert InsufficientBalance(balances[msg.sender], amount);
}
// require(string)보다 Gas 효율적
// 3. immutable과 constant
uint256 public constant MAX_SUPPLY = 10000; // 컴파일 타임 상수
address public immutable deployer; // 배포 시 설정, 이후 불변
// 둘 다 SLOAD 대신 코드에 직접 임베드 = Gas 절약
// 4. 비트 연산 활용
function isEven(uint256 n) pure returns (bool) {
return n & 1 == 0; // n % 2 == 0 보다 효율적
}
function multiplyByPowerOf2(uint256 n, uint256 pow) pure returns (uint256) {
return n << pow; // n * (2**pow)
}
9. Web3 프론트엔드 통합
9.1 ethers.js / viem
// ethers.js v6 기본 사용
// 지갑 연결
async function connectWallet() {
if (!window.ethereum) {
throw new Error("MetaMask not installed");
}
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const address = await signer.getAddress();
const balance = await provider.getBalance(address);
console.log("Address:", address);
console.log("Balance:", ethers.formatEther(balance), "ETH");
return signer;
}
// 컨트랙트 인터랙션
async function interactWithContract(signer) {
const contractAddress = "0x...";
const abi = [
"function getValue() view returns (uint256)",
"function setValue(uint256) external",
"event ValueChanged(address indexed, uint256)"
];
const contract = new Contract(contractAddress, abi, signer);
// 읽기
const value = await contract.getValue();
console.log("Current value:", value.toString());
// 쓰기
const tx = await contract.setValue(42);
await tx.wait();
console.log("Transaction confirmed:", tx.hash);
}
9.2 wagmi + viem (React)
// wagmi v2 설정
const config = createConfig({
chains: [mainnet, arbitrum, base],
connectors: [
injected(),
walletConnect({ projectId: "YOUR_PROJECT_ID" }),
],
transports: {
[mainnet.id]: http(),
[arbitrum.id]: http(),
[base.id]: http(),
},
});
// React 컴포넌트
function WalletConnect() {
const { address, isConnected } = useAccount();
const { connect } = useConnect();
const { disconnect } = useDisconnect();
const { data: balance } = useBalance({ address });
if (isConnected) {
return (
);
}
return (
Connect Wallet
);
}
10. Web3 커리어 가이드
10.1 포지션별 연봉 (2025년 기준)
| 포지션 | 경력 | 연봉 범위 (USD) |
|--------|------|-----------------|
| Junior Solidity Dev | 0-2년 | 80K-120K |
| Mid Solidity Dev | 2-4년 | 120K-180K |
| Senior Smart Contract Dev | 4년+ | 180K-250K |
| Smart Contract Auditor | 3년+ | 150K-300K+ |
| Protocol Engineer | 5년+ | 200K-350K+ |
| DeFi Researcher | 3년+ | 150K-250K |
| Web3 Frontend (React + ethers) | 2년+ | 100K-180K |
| Blockchain Infra Engineer | 3년+ | 140K-220K |
10.2 필수 기술 스택
Web3 개발자 로드맵:
기초 (3-6개월):
├── Solidity 문법 및 패턴
├── EVM 이해
├── Hardhat 또는 Foundry
├── ethers.js / viem
└── OpenZeppelin 라이브러리
중급 (6-12개월):
├── DeFi 프로토콜 이해 (AMM, Lending)
├── Security (일반 취약점 + 감사)
├── 가스 최적화
├── Layer 2 개발
├── The Graph (인덱싱)
└── IPFS / Arweave (분산 스토리지)
고급 (12개월+):
├── MEV (Maximal Extractable Value)
├── ZK Proof 기초
├── Cross-chain 브릿지
├── Account Abstraction (ERC-4337)
├── 프로토콜 설계
└── 정형 검증 (Formal Verification)
10.3 포트폴리오 전략
Web3 채용 시장에서 가장 중요한 것은 **온체인 증거**입니다.
1. **GitHub에 프로젝트 공개**: 테스트, 문서화 포함
2. **테스트넷 배포**: Sepolia, Base Goerli 등에 실제 배포
3. **감사 경험**: Code4rena, Sherlock 등의 감사 경진대회 참여
4. **기여 활동**: OpenZeppelin, Uniswap 등 OSS 기여
5. **블로그/스레드**: 기술 분석 글 공유
11. 실전 퀴즈
각 문제를 풀고 답을 확인해 보세요.
**Checks-Effects-Interactions (CEI) 패턴**
상태 확인(Checks) 후 상태 변경(Effects)을 먼저 수행하고, 마지막에 외부 호출(Interactions)을 합니다. 추가로 OpenZeppelin의 ReentrancyGuard(nonReentrant modifier)를 사용할 수 있습니다.
**검증 방식의 차이**입니다.
- Optimistic Rollup: 트랜잭션이 유효하다고 낙관적으로 가정하고, 7일간의 챌린지 기간 동안 사기 증명(Fraud Proof)으로 이의를 제기할 수 있습니다.
- ZK Rollup: 모든 트랜잭션 배치에 대해 수학적 유효성 증명(Validity Proof)을 즉시 생성하여 L1에 제출합니다. 인출이 더 빠릅니다.
**20,000 Gas** (새로운 스토리지 슬롯에 값을 기록하는 경우)
기존 값을 업데이트하는 경우는 5,000 Gas입니다. 이것이 Storage 최적화가 중요한 이유이며, 변수 패킹, constant/immutable 사용 등으로 SSTORE 호출을 줄여야 합니다.
**x * y = k (Constant Product Formula)**
x는 토큰 A의 수량, y는 토큰 B의 수량, k는 상수입니다. 한 토큰을 넣으면 k를 유지하도록 다른 토큰이 빠져나옵니다. 이 공식은 슬리피지와 가격 영향을 자연스럽게 만듭니다.
**Custom Errors** (Solidity 0.8.4+)
`error Unauthorized();`로 선언하고 `revert Unauthorized();`로 사용합니다. require에 문자열 메시지를 넣는 것보다 Gas 효율적이며, 매개변수도 포함할 수 있어 디버깅에도 유용합니다.
12. 참고 자료
1. [Ethereum 공식 문서](https://ethereum.org/developers) - Ethereum 개발 기초
2. [Solidity 공식 문서](https://docs.soliditylang.org/) - Solidity 언어 레퍼런스
3. [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/) - 검증된 스마트 컨트랙트 라이브러리
4. [Hardhat 공식 문서](https://hardhat.org/docs) - Hardhat 개발 환경
5. [Foundry Book](https://book.getfoundry.sh/) - Foundry 개발 도구
6. [Ethereum EVM Illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf) - EVM 시각 자료
7. [SWC Registry](https://swcregistry.io/) - 스마트 컨트랙트 취약점 분류
8. [DeFiLlama](https://defillama.com/) - DeFi TVL 및 프로토콜 데이터
9. [L2Beat](https://l2beat.com/) - Layer 2 비교 및 TVL 트래킹
10. [Chainlink 공식 문서](https://docs.chain.link/) - 오라클 솔루션
11. [EIP-4337: Account Abstraction](https://eips.ethereum.org/EIPS/eip-4337) - Account Abstraction 표준
12. [Secureum](https://secureum.xyz/) - 스마트 컨트랙트 보안 학습
13. [Code4rena](https://code4rena.com/) - 스마트 컨트랙트 감사 경진대회
현재 단락 (1/707)
2025년 블록체인 생태계는 투기적 광풍의 시대를 지나 실질적인 기술 인프라로 자리 잡았습니다. Ethereum의 Dencun 업그레이드, Layer 2 롤업의 폭발적 성장, 그리...